add string descriptions
This commit is contained in:
@@ -63,7 +63,7 @@ export function LoginModal(props: any) {
|
||||
<FormattedMessage defaultMessage={"Sign in"} />
|
||||
</Button>
|
||||
<Button fullWidth variant="subtle" onClick={onCreateAccountClick}>
|
||||
<FormattedMessage defaultMessage={"Or create an account"} />
|
||||
<FormattedMessage defaultMessage={"Or create an account"} description="Label for a button on the Sign In page that lets the user create an account instead" />
|
||||
</Button>
|
||||
</Container>
|
||||
</Modal>
|
||||
@@ -100,7 +100,7 @@ export function CreateAccountModal(props: any) {
|
||||
<FormattedMessage defaultMessage={"Sign up"} />
|
||||
</Button>
|
||||
<Button fullWidth variant="subtle" onClick={onSignInClick}>
|
||||
<FormattedMessage defaultMessage={"Or sign in to an existing account"} />
|
||||
<FormattedMessage defaultMessage={"Or sign in to an existing account"} description="Label for a button on the Create Account page that lets the user sign into their existing account instead" />
|
||||
</Button>
|
||||
</Container>
|
||||
</Modal>
|
||||
|
@@ -160,16 +160,16 @@ export default function Header(props: HeaderProps) {
|
||||
<Helmet>
|
||||
<title>
|
||||
{props.title ? `${props.title} - ` : ''}
|
||||
{intl.formatMessage({ defaultMessage: "Chat with GPT - Unofficial ChatGPT app" })}
|
||||
{intl.formatMessage({ defaultMessage: "Chat with GPT - Unofficial ChatGPT app", description: "HTML title tag" })}
|
||||
</title>
|
||||
</Helmet>
|
||||
{!sidebarOpen && <Burger opened={sidebarOpen} onClick={onBurgerClick} aria-label={burgerLabel} transitionDuration={0} />}
|
||||
{context.isHome && <h2>{intl.formatMessage({ defaultMessage: "Chat with GPT" })}</h2>}
|
||||
{context.isHome && <h2>{intl.formatMessage({ defaultMessage: "Chat with GPT", description: "app name" })}</h2>}
|
||||
<div className="spacer" />
|
||||
<HeaderButton icon="search" onClick={spotlight.openSpotlight} />
|
||||
<HeaderButton icon="gear" onClick={openSettings} />
|
||||
{backend.current && !props.share && props.canShare && typeof navigator.share !== 'undefined' && <HeaderButton icon="share" onClick={props.onShare}>
|
||||
<FormattedMessage defaultMessage="Share" />
|
||||
<FormattedMessage defaultMessage="Share" description="Label for the button used to create a public share URL for a chat log" />
|
||||
</HeaderButton>}
|
||||
{backend.current && !context.authenticated && (
|
||||
<HeaderButton onClick={() => {
|
||||
@@ -180,13 +180,14 @@ export default function Header(props: HeaderProps) {
|
||||
}
|
||||
}}>
|
||||
<FormattedMessage defaultMessage="Sign in <h>to sync</h>"
|
||||
description="Label for sign in button, indicating the purpose of signing in is to sync your data between devices"
|
||||
values={{
|
||||
h: (chunks: any) => <span className="hide-on-mobile">{chunks}</span>
|
||||
}} />
|
||||
</HeaderButton>
|
||||
)}
|
||||
<HeaderButton icon="plus" onClick={onNewChat} loading={loading} variant="light">
|
||||
<FormattedMessage defaultMessage="New Chat" />
|
||||
<FormattedMessage defaultMessage="New Chat" description="Label for the button used to start a new chat session" />
|
||||
</HeaderButton>
|
||||
</HeaderContainer>
|
||||
), [sidebarOpen, onBurgerClick, props.title, props.share, props.canShare, props.onShare, openSettings, onNewChat, loading, context.authenticated, context.isHome, context.isShare, spotlight.openSpotlight]);
|
||||
|
@@ -79,7 +79,7 @@ export default function MessageInput(props: MessageInputProps) {
|
||||
<Button variant="subtle" size="xs" compact onClick={() => {
|
||||
context.chat.cancelReply(context.currentChat.leaf!.id);
|
||||
}}>
|
||||
<FormattedMessage defaultMessage={"Cancel"} />
|
||||
<FormattedMessage defaultMessage={"Cancel"} description="Label for the button that can be clicked while the AI is generating a response to cancel generation" />
|
||||
</Button>
|
||||
<Loader size="xs" style={{ padding: '0 0.8rem 0 0.5rem' }} />
|
||||
</>)}
|
||||
@@ -119,7 +119,7 @@ export default function MessageInput(props: MessageInputProps) {
|
||||
compact
|
||||
onClick={onCustomizeSystemPromptClick}>
|
||||
<span>
|
||||
<FormattedMessage defaultMessage={"Customize system prompt"} />
|
||||
<FormattedMessage defaultMessage={"Customize system prompt"} description="Label for the button that opens a modal for customizing the 'system prompt', a message used to customize and influence how the AI responds." />
|
||||
</span>
|
||||
</Button>
|
||||
<Button variant="subtle"
|
||||
@@ -129,6 +129,7 @@ export default function MessageInput(props: MessageInputProps) {
|
||||
onClick={onTemperatureClick}>
|
||||
<span>
|
||||
<FormattedMessage defaultMessage="Temperature: {temperature, number, ::.0}"
|
||||
description="Label for the button that opens a modal for setting the 'temperature' (randomness) of AI responses"
|
||||
values={{ temperature }} />
|
||||
</span>
|
||||
</Button>
|
||||
|
@@ -97,7 +97,10 @@ export function Markdown(props: MarkdownProps) {
|
||||
{({ copy, copied }) => (
|
||||
<Button variant="subtle" size="sm" compact onClick={copy}>
|
||||
<i className="fa fa-clipboard" />
|
||||
<span>{copied ? <FormattedMessage defaultMessage="Copied" /> : <FormattedMessage defaultMessage="Copy" />}</span>
|
||||
<span>
|
||||
{copied ? <FormattedMessage defaultMessage="Copied" description="Label for copy-to-clipboard button after a successful copy" />
|
||||
: <FormattedMessage defaultMessage="Copy" description="Label for copy-to-clipboard button" />}
|
||||
</span>
|
||||
</Button>
|
||||
)}
|
||||
</CopyButton>
|
||||
|
@@ -208,15 +208,15 @@ export default function MessageComponent(props: { message: Message, last: boolea
|
||||
switch (role) {
|
||||
case 'user':
|
||||
if (share) {
|
||||
return intl.formatMessage({ id: 'role-user-formal', defaultMessage: 'User' });
|
||||
return intl.formatMessage({ id: 'role-user-formal', defaultMessage: 'User', description: "Label that is shown above messages written by the user (as opposed to the AI) for publicly shared conversation (third person, formal)." });
|
||||
} else {
|
||||
return intl.formatMessage({ id: 'role-user', defaultMessage: 'You' });
|
||||
return intl.formatMessage({ id: 'role-user', defaultMessage: 'You', description: "Label that is shown above messages written by the user (as opposed to the AI) in the user's own chat sessions (first person)." });
|
||||
}
|
||||
break;
|
||||
case 'assistant':
|
||||
return intl.formatMessage({ id: 'role-chatgpt', defaultMessage: 'ChatGPT' });
|
||||
return intl.formatMessage({ id: 'role-chatgpt', defaultMessage: 'ChatGPT', description: "Label that is shown above messages written by the AI (as opposed to the user)" });
|
||||
case 'system':
|
||||
return intl.formatMessage({ id: 'role-system', defaultMessage: 'System' });
|
||||
return intl.formatMessage({ id: 'role-system', defaultMessage: 'System', description: "Label that is shown above messages inserted into the conversation automatically by the system (as opposed to either the user or AI)" });
|
||||
default:
|
||||
return role;
|
||||
}
|
||||
@@ -243,7 +243,8 @@ export default function MessageComponent(props: { message: Message, last: boolea
|
||||
{({ copy, copied }) => (
|
||||
<Button variant="subtle" size="sm" compact onClick={copy} style={{ marginLeft: '1rem' }}>
|
||||
<i className="fa fa-clipboard" />
|
||||
<span>{copied ? <FormattedMessage defaultMessage="Copied" /> : <FormattedMessage defaultMessage="Copy" />}</span>
|
||||
{copied ? <FormattedMessage defaultMessage="Copied" description="Label for copy-to-clipboard button after a successful copy" />
|
||||
: <FormattedMessage defaultMessage="Copy" description="Label for copy-to-clipboard button" />}
|
||||
</Button>
|
||||
)}
|
||||
</CopyButton>
|
||||
@@ -251,7 +252,7 @@ export default function MessageComponent(props: { message: Message, last: boolea
|
||||
<Button variant="subtle" size="sm" compact onClick={() => share(props.message.content)}>
|
||||
<i className="fa fa-share" />
|
||||
<span>
|
||||
<FormattedMessage defaultMessage="Share" />
|
||||
<FormattedMessage defaultMessage="Share" description="Label for a button which shares the text of a chat message using the user device's share functionality" />
|
||||
</span>
|
||||
</Button>
|
||||
)}
|
||||
@@ -261,14 +262,17 @@ export default function MessageComponent(props: { message: Message, last: boolea
|
||||
setEditing(v => !v);
|
||||
}}>
|
||||
<i className="fa fa-edit" />
|
||||
<span>{editing ? <FormattedMessage defaultMessage="Cancel" /> : <FormattedMessage defaultMessage="Edit" />}</span>
|
||||
<span>
|
||||
{editing ? <FormattedMessage defaultMessage="Cancel" description="Label for a button that appears when the user is editing the text of one of their messages, to cancel without saving changes" />
|
||||
: <FormattedMessage defaultMessage="Edit" description="Label for the button the user can click to edit the text of one of their messages" />}
|
||||
</span>
|
||||
</Button>
|
||||
)}
|
||||
{!context.isShare && props.message.role === 'assistant' && (
|
||||
<Button variant="subtle" size="sm" compact onClick={() => context.regenerateMessage(props.message)}>
|
||||
<i className="fa fa-refresh" />
|
||||
<span>
|
||||
<FormattedMessage defaultMessage="Regenerate" />
|
||||
<FormattedMessage defaultMessage="Regenerate" description="Label for the button used to ask the AI to regenerate one of its messages. Since message generations are stochastic, the resulting message will be different." />
|
||||
</span>
|
||||
</Button>
|
||||
)}
|
||||
@@ -279,10 +283,10 @@ export default function MessageComponent(props: { message: Message, last: boolea
|
||||
onChange={e => setContent(e.currentTarget.value)}
|
||||
autosize={true} />
|
||||
<Button variant="light" onClick={() => context.editMessage(props.message, content)}>
|
||||
<FormattedMessage defaultMessage="Save changes" />
|
||||
<FormattedMessage defaultMessage="Save changes" description="Label for a button that appears when the user is editing the text of one of their messages, to save the changes" />
|
||||
</Button>
|
||||
<Button variant="subtle" onClick={() => setEditing(false)}>
|
||||
<FormattedMessage defaultMessage="Cancel" />
|
||||
<FormattedMessage defaultMessage="Cancel" description="Label for a button that appears when the user is editing the text of one of their messages, to cancel without saving changes" />
|
||||
</Button>
|
||||
</Editor>)}
|
||||
</div>
|
||||
|
@@ -27,7 +27,8 @@ export default function LandingPage(props: any) {
|
||||
return <Page id={'landing'} showSubHeader={true}>
|
||||
<Container>
|
||||
<p>
|
||||
<FormattedMessage defaultMessage={'Hello, how can I help you today?'} />
|
||||
<FormattedMessage defaultMessage={'Hello, how can I help you today?'}
|
||||
description="A friendly message that appears at the start of new chat sessions" />
|
||||
</p>
|
||||
{!openAIApiKey && (
|
||||
<Button size="xs" variant="light" compact onClick={onConnectButtonClick}>
|
||||
|
@@ -103,7 +103,9 @@ export default function SettingsDrawer(props: SettingsDrawerProps) {
|
||||
</Tabs>
|
||||
<div id="save">
|
||||
<Button variant="light" fullWidth size="md" onClick={close}>
|
||||
<FormattedMessage defaultMessage={"Save and Close"} />
|
||||
<FormattedMessage defaultMessage={"Save and Close"}
|
||||
description="Label for the button that closes the Settings screen, saving any changes"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
</Container>
|
||||
|
@@ -30,7 +30,7 @@ export default function GenerationOptionsTab(props: any) {
|
||||
&& (model?.trim() !== defaultModel.trim());
|
||||
|
||||
const systemPromptOption = useMemo(() => (
|
||||
<SettingsOption heading={intl.formatMessage({ defaultMessage: "System Prompt" })}
|
||||
<SettingsOption heading={intl.formatMessage({ defaultMessage: "System Prompt", description: "Heading for the setting that lets users customize the System Prompt, on the settings screen" })}
|
||||
focused={option === 'system-prompt'}>
|
||||
<Textarea
|
||||
value={initialSystemPrompt || defaultSystemPrompt}
|
||||
@@ -49,7 +49,7 @@ export default function GenerationOptionsTab(props: any) {
|
||||
), [option, initialSystemPrompt, resettableSystemPromopt, onSystemPromptChange, onResetSystemPrompt]);
|
||||
|
||||
const modelOption = useMemo(() => (
|
||||
<SettingsOption heading={intl.formatMessage({ defaultMessage: "Model" })}
|
||||
<SettingsOption heading={intl.formatMessage({ defaultMessage: "Model", description: "Heading for the setting that lets users choose a model to interact with, on the settings screen" })}
|
||||
focused={option === 'model'}>
|
||||
<Select
|
||||
value={model || defaultModel}
|
||||
@@ -77,7 +77,10 @@ export default function GenerationOptionsTab(props: any) {
|
||||
), [option, model, resettableModel, onModelChange, onResetModel]);
|
||||
|
||||
const temperatureOption = useMemo(() => (
|
||||
<SettingsOption heading={intl.formatMessage({ defaultMessage: "Temperature: {temperature, number, ::.0}", }, { temperature })}
|
||||
<SettingsOption heading={intl.formatMessage({
|
||||
defaultMessage: "Temperature: {temperature, number, ::.0}",
|
||||
description: "Label for the button that opens a modal for setting the 'temperature' (randomness) of AI responses",
|
||||
}, { temperature })}
|
||||
focused={option === 'temperature'}>
|
||||
<Slider value={temperature} onChange={onTemperatureChange} step={0.1} min={0} max={1} precision={3} />
|
||||
<p>
|
||||
|
@@ -33,7 +33,7 @@ export default function SpeechOptionsTab() {
|
||||
}, [elevenLabsApiKey]);
|
||||
|
||||
const apiKeyOption = useMemo(() => (
|
||||
<SettingsOption heading={intl.formatMessage({ defaultMessage: 'Your ElevenLabs Text-to-Speech API Key (optional)' })}
|
||||
<SettingsOption heading={intl.formatMessage({ defaultMessage: 'Your ElevenLabs Text-to-Speech API Key (optional)', description: "Heading for the ElevenLabs API key setting on the settings screen" })}
|
||||
focused={option === 'elevenlabs-api-key'}>
|
||||
<TextInput placeholder={intl.formatMessage({ defaultMessage: "Paste your API key here" })}
|
||||
value={elevenLabsApiKey || ''} onChange={onElevenLabsApiKeyChange} />
|
||||
@@ -50,7 +50,7 @@ export default function SpeechOptionsTab() {
|
||||
), [option, elevenLabsApiKey, onElevenLabsApiKeyChange]);
|
||||
|
||||
const voiceOption = useMemo(() => (
|
||||
<SettingsOption heading={intl.formatMessage({ defaultMessage: 'Voice' })}
|
||||
<SettingsOption heading={intl.formatMessage({ defaultMessage: 'Voice', description: 'Heading for the setting that lets users choose an ElevenLabs text-to-speech voice, on the settings screen' })}
|
||||
focused={option === 'elevenlabs-voice'}>
|
||||
<Select
|
||||
value={voice}
|
||||
@@ -64,7 +64,7 @@ export default function SpeechOptionsTab() {
|
||||
<Button onClick={() => (document.getElementById('voice-preview') as HTMLMediaElement)?.play()} variant='light' compact style={{ marginTop: '1rem' }}>
|
||||
<i className='fa fa-headphones' />
|
||||
<span>
|
||||
<FormattedMessage defaultMessage="Preview voice" />
|
||||
<FormattedMessage defaultMessage="Preview voice" description="Label for the button that plays a preview of the selected ElevenLabs text-to-speech voice" />
|
||||
</span>
|
||||
</Button>
|
||||
</SettingsOption>
|
||||
|
@@ -17,7 +17,7 @@ export default function UserOptionsTab(props: any) {
|
||||
|
||||
const elem = useMemo(() => (
|
||||
<SettingsTab name="user">
|
||||
<SettingsOption heading={intl.formatMessage({ defaultMessage: "Your OpenAI API Key" })}
|
||||
<SettingsOption heading={intl.formatMessage({ defaultMessage: "Your OpenAI API Key", description: "Heading for the OpenAI API key setting on the settings screen" })}
|
||||
focused={option === 'openai-api-key'}>
|
||||
<TextInput
|
||||
placeholder={intl.formatMessage({ defaultMessage: "Paste your API key here" })}
|
||||
@@ -25,7 +25,7 @@ export default function UserOptionsTab(props: any) {
|
||||
onChange={onOpenAIApiKeyChange} />
|
||||
<p>
|
||||
<a href="https://platform.openai.com/account/api-keys" target="_blank" rel="noreferrer">
|
||||
<FormattedMessage defaultMessage="Find your API key here." />
|
||||
<FormattedMessage defaultMessage="Find your API key here." description="Label for the link that takes the user to the page on the OpenAI website where they can find their API key." />
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
|
@@ -115,7 +115,7 @@ export default function Sidebar(props: {
|
||||
const elem = useMemo(() => (
|
||||
<Container className={"sidebar " + (sidebarOpen ? 'opened' : 'closed')} ref={ref}>
|
||||
<div className="sidebar-header">
|
||||
<h2><FormattedMessage defaultMessage={"Chat History"} /></h2>
|
||||
<h2><FormattedMessage defaultMessage={"Chat History"} description="Heading for the chat history screen" /></h2>
|
||||
<Burger opened={sidebarOpen} onClick={onBurgerClick} aria-label={burgerLabel} transitionDuration={0} />
|
||||
</div>
|
||||
<div className="sidebar-content">
|
||||
@@ -141,7 +141,7 @@ export default function Sidebar(props: {
|
||||
<Menu.Item onClick={() => {
|
||||
dispatch(setTab('user'));
|
||||
}} icon={<i className="fas fa-gear" />}>
|
||||
<FormattedMessage defaultMessage={"User settings"} />
|
||||
<FormattedMessage defaultMessage={"User settings"} description="Menu item that opens the user settings screen" />
|
||||
</Menu.Item>
|
||||
{/*
|
||||
<Menu.Divider />
|
||||
|
@@ -84,12 +84,12 @@ export default function RecentChats(props: any) {
|
||||
onClick={onClick}
|
||||
data-chat-id={c.chatID}
|
||||
className={c.chatID === currentChatID ? 'selected' : ''}>
|
||||
<strong>{c.title || <FormattedMessage defaultMessage={"Untitled"} />}</strong>
|
||||
<strong>{c.title || <FormattedMessage defaultMessage={"Untitled"} description="default title for untitled chat sessions" />}</strong>
|
||||
</ChatListItem>
|
||||
))}
|
||||
</ChatList>}
|
||||
{recentChats.length === 0 && <Empty>
|
||||
<FormattedMessage defaultMessage={"No chats yet."} />
|
||||
<FormattedMessage defaultMessage={"No chats yet."} description="Message shown on the Chat History screen for new users who haven't started their first chat session" />
|
||||
</Empty>}
|
||||
</Container>
|
||||
);
|
||||
|
@@ -47,11 +47,17 @@ const root = ReactDOM.createRoot(
|
||||
);
|
||||
|
||||
async function loadLocaleData(locale: string) {
|
||||
const messages = await fetch(`/lang/${locale}.json`);
|
||||
if (!messages.ok) {
|
||||
const response = await fetch(`/lang/${locale}.json`);
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to load locale data");
|
||||
}
|
||||
return messages.json()
|
||||
const messages: any = await response.json();
|
||||
for (const key of Object.keys(messages)) {
|
||||
if (typeof messages[key] !== 'string') {
|
||||
messages[key] = messages[key].defaultMessage;
|
||||
}
|
||||
}
|
||||
return messages;
|
||||
}
|
||||
|
||||
async function bootstrapApplication() {
|
||||
|
@@ -272,13 +272,13 @@ export function ElevenLabsReaderButton(props: { selector: string }) {
|
||||
<Button variant="subtle" size="sm" compact onClickCapture={onClick} loading={status === 'init'}>
|
||||
{status !== 'init' && <i className="fa fa-headphones" />}
|
||||
{status === 'idle' && <span>
|
||||
<FormattedMessage defaultMessage="Play" />
|
||||
<FormattedMessage defaultMessage="Play" description="Label for the button that starts text-to-speech playback" />
|
||||
</span>}
|
||||
{status === 'buffering' && <span>
|
||||
<FormattedMessage defaultMessage="Loading audio..." />
|
||||
<FormattedMessage defaultMessage="Loading audio..." description="Message indicating that text-to-speech audio is buffering" />
|
||||
</span>}
|
||||
{status !== 'idle' && status !== 'buffering' && <span>
|
||||
<FormattedMessage defaultMessage="Stop" />
|
||||
<FormattedMessage defaultMessage="Stop" description="Label for the button that stops text-to-speech playback" />
|
||||
</span>}
|
||||
</Button>
|
||||
);
|
||||
|
Reference in New Issue
Block a user