feat(desktop): add i18n infrastructure with react-intl (#8105)

This commit is contained in:
jh-block
2026-03-27 19:39:50 +01:00
committed by GitHub
parent d596113e72
commit a6765fbcd9
172 changed files with 13793 additions and 2054 deletions
@@ -2,6 +2,58 @@ import React, { useState, useEffect } from 'react';
import { Parameter } from '../recipe';
import { Button } from './ui/button';
import { getInitialWorkingDir } from '../utils/workingDir';
import { defineMessages, useIntl } from '../i18n';
const i18n = defineMessages({
cancelRecipeSetup: {
id: 'parameterInputModal.cancelRecipeSetup',
defaultMessage: 'Cancel Recipe Setup',
},
whatToDo: {
id: 'parameterInputModal.whatToDo',
defaultMessage: 'What would you like to do?',
},
backToForm: {
id: 'parameterInputModal.backToForm',
defaultMessage: 'Back to Parameter Form',
},
startNewChat: {
id: 'parameterInputModal.startNewChat',
defaultMessage: 'Start New Chat (No Recipe)',
},
recipeParameters: {
id: 'parameterInputModal.recipeParameters',
defaultMessage: 'Recipe Parameters',
},
selectOption: {
id: 'parameterInputModal.selectOption',
defaultMessage: 'Select an option...',
},
select: {
id: 'parameterInputModal.select',
defaultMessage: 'Select...',
},
true: {
id: 'parameterInputModal.true',
defaultMessage: 'True',
},
false: {
id: 'parameterInputModal.false',
defaultMessage: 'False',
},
enterValue: {
id: 'parameterInputModal.enterValue',
defaultMessage: 'Enter value for {key}...',
},
cancel: {
id: 'parameterInputModal.cancel',
defaultMessage: 'Cancel',
},
startRecipe: {
id: 'parameterInputModal.startRecipe',
defaultMessage: 'Start Recipe',
},
});
interface ParameterInputModalProps {
parameters: Parameter[];
@@ -16,6 +68,7 @@ const ParameterInputModal: React.FC<ParameterInputModalProps> = ({
onClose,
initialValues,
}) => {
const intl = useIntl();
const [inputValues, setInputValues] = useState<Record<string, string>>({});
const [validationErrors, setValidationErrors] = useState<Record<string, string>>({});
const [showCancelOptions, setShowCancelOptions] = useState(false);
@@ -91,8 +144,10 @@ const ParameterInputModal: React.FC<ParameterInputModalProps> = ({
{showCancelOptions ? (
// Cancel options modal
<div className="bg-background-primary border border-border-primary rounded-xl p-8 shadow-2xl w-full max-w-md">
<h2 className="text-xl font-bold text-text-primary mb-4">Cancel Recipe Setup</h2>
<p className="text-text-primary mb-6">What would you like to do?</p>
<h2 className="text-xl font-bold text-text-primary mb-4">
{intl.formatMessage(i18n.cancelRecipeSetup)}
</h2>
<p className="text-text-primary mb-6">{intl.formatMessage(i18n.whatToDo)}</p>
<div className="flex flex-col gap-3">
<Button
onClick={() => handleCancelOption('back-to-form')}
@@ -100,7 +155,7 @@ const ParameterInputModal: React.FC<ParameterInputModalProps> = ({
size="lg"
className="w-full rounded-full"
>
Back to Parameter Form
{intl.formatMessage(i18n.backToForm)}
</Button>
<Button
onClick={() => handleCancelOption('new-chat')}
@@ -108,7 +163,7 @@ const ParameterInputModal: React.FC<ParameterInputModalProps> = ({
size="lg"
className="w-full rounded-full"
>
Start New Chat (No Recipe)
{intl.formatMessage(i18n.startNewChat)}
</Button>
</div>
</div>
@@ -116,7 +171,9 @@ const ParameterInputModal: React.FC<ParameterInputModalProps> = ({
// Main parameter form
<div className="bg-background-primary border border-border-primary rounded-xl shadow-2xl w-full max-w-lg max-h-[90vh] flex flex-col overflow-hidden">
<div className="p-8 pb-4 flex-shrink-0">
<h2 className="text-xl font-bold text-text-primary mb-6">Recipe Parameters</h2>
<h2 className="text-xl font-bold text-text-primary mb-6">
{intl.formatMessage(i18n.recipeParameters)}
</h2>
</div>
<div className="flex-1 overflow-y-auto px-8">
<form onSubmit={handleSubmit} className="space-y-4 mb-4">
@@ -140,7 +197,7 @@ const ParameterInputModal: React.FC<ParameterInputModalProps> = ({
: 'border-border-primary focus:ring-border-secondary'
}`}
>
<option value="">Select an option...</option>
<option value="">{intl.formatMessage(i18n.selectOption)}</option>
{param.options.map((option) => (
<option key={option} value={option}>
{option}
@@ -157,9 +214,9 @@ const ParameterInputModal: React.FC<ParameterInputModalProps> = ({
: 'border-border-primary focus:ring-border-secondary'
}`}
>
<option value="">Select...</option>
<option value="true">True</option>
<option value="false">False</option>
<option value="">{intl.formatMessage(i18n.select)}</option>
<option value="true">{intl.formatMessage(i18n.true)}</option>
<option value="false">{intl.formatMessage(i18n.false)}</option>
</select>
) : (
<input
@@ -171,7 +228,7 @@ const ParameterInputModal: React.FC<ParameterInputModalProps> = ({
? 'border-red-500 focus:ring-red-500'
: 'border-border-primary focus:ring-border-secondary'
}`}
placeholder={param.default || `Enter value for ${param.key}...`}
placeholder={param.default || intl.formatMessage(i18n.enterValue, { key: param.key })}
/>
)}
@@ -191,7 +248,7 @@ const ParameterInputModal: React.FC<ParameterInputModalProps> = ({
size="default"
className="rounded-full"
>
Cancel
{intl.formatMessage(i18n.cancel)}
</Button>
<Button
type="button"
@@ -200,7 +257,7 @@ const ParameterInputModal: React.FC<ParameterInputModalProps> = ({
size="default"
className="rounded-full"
>
Start Recipe
{intl.formatMessage(i18n.startRecipe)}
</Button>
</div>
</div>