feat(desktop): add i18n infrastructure with react-intl (#8105)
This commit is contained in:
@@ -1,6 +1,87 @@
|
||||
import React from 'react';
|
||||
import { AlertTriangle, Trash2, ChevronDown, ChevronRight } from 'lucide-react';
|
||||
import { Parameter } from '../../recipe';
|
||||
import { defineMessages, useIntl } from '../../i18n';
|
||||
|
||||
const i18n = defineMessages({
|
||||
unusedWarningTitle: {
|
||||
id: 'parameterInput.unusedWarningTitle',
|
||||
defaultMessage:
|
||||
'This parameter is not used in the instructions or prompt. It will be available for manual input but may not be needed.',
|
||||
},
|
||||
unused: {
|
||||
id: 'parameterInput.unused',
|
||||
defaultMessage: 'Unused',
|
||||
},
|
||||
deleteParameter: {
|
||||
id: 'parameterInput.deleteParameter',
|
||||
defaultMessage: 'Delete parameter: {key}',
|
||||
},
|
||||
description: {
|
||||
id: 'parameterInput.description',
|
||||
defaultMessage: 'description',
|
||||
},
|
||||
descriptionPlaceholder: {
|
||||
id: 'parameterInput.descriptionPlaceholder',
|
||||
defaultMessage: 'E.g., "Enter the name for the new component"',
|
||||
},
|
||||
descriptionHelp: {
|
||||
id: 'parameterInput.descriptionHelp',
|
||||
defaultMessage: 'This is the message the end-user will see.',
|
||||
},
|
||||
inputType: {
|
||||
id: 'parameterInput.inputType',
|
||||
defaultMessage: 'Input Type',
|
||||
},
|
||||
typeString: {
|
||||
id: 'parameterInput.typeString',
|
||||
defaultMessage: 'String',
|
||||
},
|
||||
typeSelect: {
|
||||
id: 'parameterInput.typeSelect',
|
||||
defaultMessage: 'Select',
|
||||
},
|
||||
typeNumber: {
|
||||
id: 'parameterInput.typeNumber',
|
||||
defaultMessage: 'Number',
|
||||
},
|
||||
typeBoolean: {
|
||||
id: 'parameterInput.typeBoolean',
|
||||
defaultMessage: 'Boolean',
|
||||
},
|
||||
requirement: {
|
||||
id: 'parameterInput.requirement',
|
||||
defaultMessage: 'Requirement',
|
||||
},
|
||||
required: {
|
||||
id: 'parameterInput.required',
|
||||
defaultMessage: 'Required',
|
||||
},
|
||||
optional: {
|
||||
id: 'parameterInput.optional',
|
||||
defaultMessage: 'Optional',
|
||||
},
|
||||
defaultValue: {
|
||||
id: 'parameterInput.defaultValue',
|
||||
defaultMessage: 'Default Value',
|
||||
},
|
||||
defaultValuePlaceholder: {
|
||||
id: 'parameterInput.defaultValuePlaceholder',
|
||||
defaultMessage: 'Enter default value',
|
||||
},
|
||||
optionsLabel: {
|
||||
id: 'parameterInput.optionsLabel',
|
||||
defaultMessage: 'Options (one per line)',
|
||||
},
|
||||
optionsPlaceholder: {
|
||||
id: 'parameterInput.optionsPlaceholder',
|
||||
defaultMessage: 'Option 1\nOption 2\nOption 3',
|
||||
},
|
||||
optionsHelp: {
|
||||
id: 'parameterInput.optionsHelp',
|
||||
defaultMessage: 'Enter each option on a new line. These will be shown as dropdown choices.',
|
||||
},
|
||||
});
|
||||
|
||||
interface ParameterInputProps {
|
||||
parameter: Parameter;
|
||||
@@ -19,6 +100,7 @@ const ParameterInput: React.FC<ParameterInputProps> = ({
|
||||
isExpanded = true,
|
||||
onToggleExpanded,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const { key, description, requirement } = parameter;
|
||||
const defaultValue = parameter.default || '';
|
||||
|
||||
@@ -61,10 +143,10 @@ const ParameterInput: React.FC<ParameterInputProps> = ({
|
||||
{isUnused && (
|
||||
<div
|
||||
className="flex items-center gap-1"
|
||||
title="This parameter is not used in the instructions or prompt. It will be available for manual input but may not be needed."
|
||||
title={intl.formatMessage(i18n.unusedWarningTitle)}
|
||||
>
|
||||
<AlertTriangle className="w-4 h-4 text-orange-500" />
|
||||
<span className="text-xs text-orange-500 font-normal">Unused</span>
|
||||
<span className="text-xs text-orange-500 font-normal">{intl.formatMessage(i18n.unused)}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -78,7 +160,7 @@ const ParameterInput: React.FC<ParameterInputProps> = ({
|
||||
onDelete(key);
|
||||
}}
|
||||
className="p-1 text-red-500 hover:text-red-700 hover:bg-red-50 rounded transition-colors"
|
||||
title={`Delete parameter: ${key}`}
|
||||
title={intl.formatMessage(i18n.deleteParameter, { key })}
|
||||
>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
</button>
|
||||
@@ -91,17 +173,17 @@ const ParameterInput: React.FC<ParameterInputProps> = ({
|
||||
<div className="pt-4">
|
||||
<div className="mb-4">
|
||||
<label className="block text-md text-text-primary mb-2 font-semibold">
|
||||
description
|
||||
{intl.formatMessage(i18n.description)}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={description || ''}
|
||||
onChange={(e) => onChange(key, { description: e.target.value })}
|
||||
className="w-full p-3 border rounded-lg bg-background-primary text-text-primary focus:outline-none focus:ring-2 focus:ring-border-secondary"
|
||||
placeholder={`E.g., "Enter the name for the new component"`}
|
||||
placeholder={intl.formatMessage(i18n.descriptionPlaceholder)}
|
||||
/>
|
||||
<p className="text-sm text-text-secondary mt-1">
|
||||
This is the message the end-user will see.
|
||||
{intl.formatMessage(i18n.descriptionHelp)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -109,7 +191,7 @@ const ParameterInput: React.FC<ParameterInputProps> = ({
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="block text-md text-text-primary mb-2 font-semibold">
|
||||
Input Type
|
||||
{intl.formatMessage(i18n.inputType)}
|
||||
</label>
|
||||
<select
|
||||
className="w-full p-3 border rounded-lg bg-background-primary text-text-primary"
|
||||
@@ -118,16 +200,16 @@ const ParameterInput: React.FC<ParameterInputProps> = ({
|
||||
onChange(key, { input_type: e.target.value as Parameter['input_type'] })
|
||||
}
|
||||
>
|
||||
<option value="string">String</option>
|
||||
<option value="select">Select</option>
|
||||
<option value="number">Number</option>
|
||||
<option value="boolean">Boolean</option>
|
||||
<option value="string">{intl.formatMessage(i18n.typeString)}</option>
|
||||
<option value="select">{intl.formatMessage(i18n.typeSelect)}</option>
|
||||
<option value="number">{intl.formatMessage(i18n.typeNumber)}</option>
|
||||
<option value="boolean">{intl.formatMessage(i18n.typeBoolean)}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-md text-text-primary mb-2 font-semibold">
|
||||
Requirement
|
||||
{intl.formatMessage(i18n.requirement)}
|
||||
</label>
|
||||
<select
|
||||
className="w-full p-3 border rounded-lg bg-background-primary text-text-primary"
|
||||
@@ -136,8 +218,8 @@ const ParameterInput: React.FC<ParameterInputProps> = ({
|
||||
onChange(key, { requirement: e.target.value as Parameter['requirement'] })
|
||||
}
|
||||
>
|
||||
<option value="required">Required</option>
|
||||
<option value="optional">Optional</option>
|
||||
<option value="required">{intl.formatMessage(i18n.required)}</option>
|
||||
<option value="optional">{intl.formatMessage(i18n.optional)}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -145,14 +227,14 @@ const ParameterInput: React.FC<ParameterInputProps> = ({
|
||||
{requirement === 'optional' && (
|
||||
<div>
|
||||
<label className="block text-md text-text-primary mb-2 font-semibold">
|
||||
Default Value
|
||||
{intl.formatMessage(i18n.defaultValue)}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={defaultValue}
|
||||
onChange={(e) => onChange(key, { default: e.target.value })}
|
||||
className="w-full p-3 border rounded-lg bg-background-primary text-text-primary"
|
||||
placeholder="Enter default value"
|
||||
placeholder={intl.formatMessage(i18n.defaultValuePlaceholder)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -162,7 +244,7 @@ const ParameterInput: React.FC<ParameterInputProps> = ({
|
||||
{parameter.input_type === 'select' && (
|
||||
<div className="mt-4">
|
||||
<label className="block text-md text-text-primary mb-2 font-semibold">
|
||||
Options (one per line)
|
||||
{intl.formatMessage(i18n.optionsLabel)}
|
||||
</label>
|
||||
<textarea
|
||||
value={(parameter.options || []).join('\n')}
|
||||
@@ -178,11 +260,11 @@ const ParameterInput: React.FC<ParameterInputProps> = ({
|
||||
}
|
||||
}}
|
||||
className="w-full p-3 border rounded-lg bg-background-primary text-text-primary focus:outline-none focus:ring-2 focus:ring-border-secondary"
|
||||
placeholder="Option 1 Option 2 Option 3"
|
||||
placeholder={intl.formatMessage(i18n.optionsPlaceholder)}
|
||||
rows={4}
|
||||
/>
|
||||
<p className="text-sm text-text-secondary mt-1">
|
||||
Enter each option on a new line. These will be shown as dropdown choices.
|
||||
{intl.formatMessage(i18n.optionsHelp)}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user