Commit 03814018e6197be9fba922e8697798129e580233

Authored by zichun
1 parent 79009234

feat(web): i18n for remaining edit pages (Location, SO, PO, WO)

Add 15 new message keys for the four Edit*Page components that
were missed in the first pass. All hardcoded labels, hints, and
error messages now go through useT().
web/src/i18n/messages.ts
... ... @@ -448,6 +448,22 @@ export const en = {
448 448 // ─── User status labels ───────────────────────────────────
449 449 'label.activeStatus': 'Active',
450 450 'label.disabled': 'Disabled',
  451 +
  452 + // ─── Edit order pages ─────────────────────────────────────
  453 + 'page.editLocation.title': 'Edit {code}',
  454 + 'page.editLocation.subtitle': 'Type: {type} (read-only after creation)',
  455 + 'page.editSalesOrder.title': 'Edit {code}',
  456 + 'page.editSalesOrder.subtitle': 'Customer: {partner}',
  457 + 'page.editSalesOrder.readOnlyHint': 'Order code, partner, lines, and currency are read-only after creation. Use this form to update custom fields.',
  458 + 'page.editSalesOrder.notEditable': 'This sales order is in {status} status and cannot be edited. Only DRAFT orders are editable.',
  459 + 'page.editPurchaseOrder.title': 'Edit {code}',
  460 + 'page.editPurchaseOrder.subtitle': 'Supplier: {partner}',
  461 + 'page.editPurchaseOrder.readOnlyHint': 'Order code, partner, lines, and currency are read-only after creation. Use this form to update custom fields.',
  462 + 'page.editPurchaseOrder.notEditable': 'This purchase order is in {status} status and cannot be edited. Only DRAFT orders are editable.',
  463 + 'page.editWorkOrder.title': 'Edit {code}',
  464 + 'page.editWorkOrder.subtitle': 'Output: {item}',
  465 + 'page.editWorkOrder.readOnlyHint': 'Order code, output item, BOM inputs, and routing operations are read-only after creation.',
  466 + 'page.editWorkOrder.notEditable': 'This work order is in {status} status and cannot be edited. Only DRAFT orders are editable.',
451 467 } as const
452 468  
453 469 export const zhCN: Record<MessageKey, string> = {
... ... @@ -887,6 +903,22 @@ export const zhCN: Record&lt;MessageKey, string&gt; = {
887 903 // ─── 用户状态标签 ────────────────────────────────────────
888 904 'label.activeStatus': '已启用',
889 905 'label.disabled': '已禁用',
  906 +
  907 + // ─── 编辑订单页面 ────────────────────────────────────────
  908 + 'page.editLocation.title': '编辑 {code}',
  909 + 'page.editLocation.subtitle': '类型: {type}(创建后只读)',
  910 + 'page.editSalesOrder.title': '编辑 {code}',
  911 + 'page.editSalesOrder.subtitle': '客户: {partner}',
  912 + 'page.editSalesOrder.readOnlyHint': '订单编码、合作伙伴、行项目和币种创建后只读。使用此表单更新自定义字段。',
  913 + 'page.editSalesOrder.notEditable': '此销售订单处于 {status} 状态,无法编辑。只有草稿状态的订单可编辑。',
  914 + 'page.editPurchaseOrder.title': '编辑 {code}',
  915 + 'page.editPurchaseOrder.subtitle': '供应商: {partner}',
  916 + 'page.editPurchaseOrder.readOnlyHint': '订单编码、合作伙伴、行项目和币种创建后只读。使用此表单更新自定义字段。',
  917 + 'page.editPurchaseOrder.notEditable': '此采购订单处于 {status} 状态,无法编辑。只有草稿状态的订单可编辑。',
  918 + 'page.editWorkOrder.title': '编辑 {code}',
  919 + 'page.editWorkOrder.subtitle': '产出: {item}',
  920 + 'page.editWorkOrder.readOnlyHint': '工单编码、产出物料、BOM 投入和工艺路线创建后只读。',
  921 + 'page.editWorkOrder.notEditable': '此工单处于 {status} 状态,无法编辑。只有草稿状态的工单可编辑。',
890 922 }
891 923  
892 924 export const locales = {
... ...
web/src/pages/EditLocationPage.tsx
... ... @@ -6,10 +6,12 @@ import { PageHeader } from &#39;@/components/PageHeader&#39;
6 6 import { Loading } from '@/components/Loading'
7 7 import { ErrorBox } from '@/components/ErrorBox'
8 8 import { DynamicExtFields } from '@/components/DynamicExtFields'
  9 +import { useT } from '@/i18n/LocaleContext'
9 10  
10 11 export function EditLocationPage() {
11 12 const { id = '' } = useParams<{ id: string }>()
12 13 const navigate = useNavigate()
  14 + const t = useT()
13 15 const [location, setLocation] = useState<Location | null>(null)
14 16 const [name, setName] = useState('')
15 17 const [active, setActive] = useState(true)
... ... @@ -53,25 +55,25 @@ export function EditLocationPage() {
53 55 return (
54 56 <div>
55 57 <PageHeader
56   - title={`Edit ${location.code}`}
57   - subtitle={`Type: ${location.type} (read-only after creation)`}
58   - actions={<button className="btn-secondary" onClick={() => navigate('/locations')}>Cancel</button>}
  58 + title={t('page.editLocation.title').replace('{code}', location.code)}
  59 + subtitle={t('page.editLocation.subtitle').replace('{type}', location.type)}
  60 + actions={<button className="btn-secondary" onClick={() => navigate('/locations')}>{t('action.cancel')}</button>}
59 61 />
60 62 <form onSubmit={onSubmit} className="card p-6 space-y-4 max-w-2xl">
61 63 <div>
62   - <label className="block text-sm font-medium text-slate-700">Name</label>
  64 + <label className="block text-sm font-medium text-slate-700">{t('label.name')}</label>
63 65 <input type="text" required value={name} onChange={(e) => setName(e.target.value)}
64 66 className="mt-1 w-full rounded-md border border-slate-300 px-3 py-2 text-sm" />
65 67 </div>
66 68 <div className="flex items-center gap-2">
67 69 <input type="checkbox" checked={active} onChange={(e) => setActive(e.target.checked)}
68 70 className="rounded border-slate-300" id="active" />
69   - <label htmlFor="active" className="text-sm text-slate-700">Active</label>
  71 + <label htmlFor="active" className="text-sm text-slate-700">{t('label.active')}</label>
70 72 </div>
71 73 <DynamicExtFields entityName="Location" values={ext} onChange={(k, v) => setExt(prev => ({ ...prev, [k]: v }))} />
72 74 {error && <ErrorBox error={error} />}
73 75 <button type="submit" className="btn-primary" disabled={submitting}>
74   - {submitting ? 'Saving\u2026' : 'Save Changes'}
  76 + {submitting ? t('action.saving') : t('action.saveChanges')}
75 77 </button>
76 78 </form>
77 79 </div>
... ...
web/src/pages/EditPurchaseOrderPage.tsx
... ... @@ -6,10 +6,12 @@ import { PageHeader } from &#39;@/components/PageHeader&#39;
6 6 import { Loading } from '@/components/Loading'
7 7 import { ErrorBox } from '@/components/ErrorBox'
8 8 import { DynamicExtFields } from '@/components/DynamicExtFields'
  9 +import { useT } from '@/i18n/LocaleContext'
9 10  
10 11 export function EditPurchaseOrderPage() {
11 12 const { id = '' } = useParams<{ id: string }>()
12 13 const navigate = useNavigate()
  14 + const t = useT()
13 15 const [order, setOrder] = useState<PurchaseOrder | null>(null)
14 16 const [loading, setLoading] = useState(true)
15 17 const [ext, setExt] = useState<Record<string, unknown>>({})
... ... @@ -50,24 +52,23 @@ export function EditPurchaseOrderPage() {
50 52 return (
51 53 <div>
52 54 <PageHeader
53   - title={`Edit ${order.code}`}
54   - subtitle={`Supplier: ${order.partnerCode} \u00b7 ${order.orderDate} \u00b7 ${order.currencyCode}`}
55   - actions={<button className="btn-secondary" onClick={() => navigate(`/purchase-orders/${id}`)}>Cancel</button>}
  55 + title={t('page.editPurchaseOrder.title').replace('{code}', order.code)}
  56 + subtitle={`${t('page.editPurchaseOrder.subtitle').replace('{partner}', order.partnerCode)} \u00B7 ${order.orderDate} \u00B7 ${order.currencyCode}`}
  57 + actions={<button className="btn-secondary" onClick={() => navigate(`/purchase-orders/${id}`)}>{t('action.cancel')}</button>}
56 58 />
57 59 {!editable ? (
58 60 <div className="card p-6 max-w-2xl">
59   - <ErrorBox error={`This purchase order is in ${order.status} status and cannot be edited. Only DRAFT orders are editable.`} />
  61 + <ErrorBox error={t('page.editPurchaseOrder.notEditable').replace('{status}', order.status)} />
60 62 </div>
61 63 ) : (
62 64 <form onSubmit={onSubmit} className="card p-6 space-y-4 max-w-2xl">
63 65 <div className="rounded-md border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-600">
64   - Order code, partner, lines, and currency are read-only after creation.
65   - Use this form to update custom fields.
  66 + {t('page.editPurchaseOrder.readOnlyHint')}
66 67 </div>
67 68 <DynamicExtFields entityName="PurchaseOrder" values={ext} onChange={(k, v) => setExt(prev => ({ ...prev, [k]: v }))} />
68 69 {error && <ErrorBox error={error} />}
69 70 <button type="submit" className="btn-primary" disabled={submitting}>
70   - {submitting ? 'Saving\u2026' : 'Save Changes'}
  71 + {submitting ? t('action.saving') : t('action.saveChanges')}
71 72 </button>
72 73 </form>
73 74 )}
... ...
web/src/pages/EditSalesOrderPage.tsx
... ... @@ -6,10 +6,12 @@ import { PageHeader } from &#39;@/components/PageHeader&#39;
6 6 import { Loading } from '@/components/Loading'
7 7 import { ErrorBox } from '@/components/ErrorBox'
8 8 import { DynamicExtFields } from '@/components/DynamicExtFields'
  9 +import { useT } from '@/i18n/LocaleContext'
9 10  
10 11 export function EditSalesOrderPage() {
11 12 const { id = '' } = useParams<{ id: string }>()
12 13 const navigate = useNavigate()
  14 + const t = useT()
13 15 const [order, setOrder] = useState<SalesOrder | null>(null)
14 16 const [loading, setLoading] = useState(true)
15 17 const [ext, setExt] = useState<Record<string, unknown>>({})
... ... @@ -50,24 +52,23 @@ export function EditSalesOrderPage() {
50 52 return (
51 53 <div>
52 54 <PageHeader
53   - title={`Edit ${order.code}`}
54   - subtitle={`Customer: ${order.partnerCode} \u00b7 ${order.orderDate} \u00b7 ${order.currencyCode}`}
55   - actions={<button className="btn-secondary" onClick={() => navigate(`/sales-orders/${id}`)}>Cancel</button>}
  55 + title={t('page.editSalesOrder.title').replace('{code}', order.code)}
  56 + subtitle={`${t('page.editSalesOrder.subtitle').replace('{partner}', order.partnerCode)} \u00B7 ${order.orderDate} \u00B7 ${order.currencyCode}`}
  57 + actions={<button className="btn-secondary" onClick={() => navigate(`/sales-orders/${id}`)}>{t('action.cancel')}</button>}
56 58 />
57 59 {!editable ? (
58 60 <div className="card p-6 max-w-2xl">
59   - <ErrorBox error={`This sales order is in ${order.status} status and cannot be edited. Only DRAFT orders are editable.`} />
  61 + <ErrorBox error={t('page.editSalesOrder.notEditable').replace('{status}', order.status)} />
60 62 </div>
61 63 ) : (
62 64 <form onSubmit={onSubmit} className="card p-6 space-y-4 max-w-2xl">
63 65 <div className="rounded-md border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-600">
64   - Order code, partner, lines, and currency are read-only after creation.
65   - Use this form to update custom fields.
  66 + {t('page.editSalesOrder.readOnlyHint')}
66 67 </div>
67 68 <DynamicExtFields entityName="SalesOrder" values={ext} onChange={(k, v) => setExt(prev => ({ ...prev, [k]: v }))} />
68 69 {error && <ErrorBox error={error} />}
69 70 <button type="submit" className="btn-primary" disabled={submitting}>
70   - {submitting ? 'Saving\u2026' : 'Save Changes'}
  71 + {submitting ? t('action.saving') : t('action.saveChanges')}
71 72 </button>
72 73 </form>
73 74 )}
... ...
web/src/pages/EditWorkOrderPage.tsx
... ... @@ -6,10 +6,12 @@ import { PageHeader } from &#39;@/components/PageHeader&#39;
6 6 import { Loading } from '@/components/Loading'
7 7 import { ErrorBox } from '@/components/ErrorBox'
8 8 import { DynamicExtFields } from '@/components/DynamicExtFields'
  9 +import { useT } from '@/i18n/LocaleContext'
9 10  
10 11 export function EditWorkOrderPage() {
11 12 const { id = '' } = useParams<{ id: string }>()
12 13 const navigate = useNavigate()
  14 + const t = useT()
13 15 const [order, setOrder] = useState<WorkOrder | null>(null)
14 16 const [outputQuantity, setOutputQuantity] = useState('')
15 17 const [dueDate, setDueDate] = useState('')
... ... @@ -56,28 +58,28 @@ export function EditWorkOrderPage() {
56 58 return (
57 59 <div>
58 60 <PageHeader
59   - title={`Edit ${order.code}`}
60   - subtitle={`Output: ${order.outputItemCode}`}
61   - actions={<button className="btn-secondary" onClick={() => navigate(`/work-orders/${id}`)}>Cancel</button>}
  61 + title={t('page.editWorkOrder.title').replace('{code}', order.code)}
  62 + subtitle={t('page.editWorkOrder.subtitle').replace('{item}', order.outputItemCode)}
  63 + actions={<button className="btn-secondary" onClick={() => navigate(`/work-orders/${id}`)}>{t('action.cancel')}</button>}
62 64 />
63 65 {!editable ? (
64 66 <div className="card p-6 max-w-2xl">
65   - <ErrorBox error={`This work order is in ${order.status} status and cannot be edited. Only DRAFT orders are editable.`} />
  67 + <ErrorBox error={t('page.editWorkOrder.notEditable').replace('{status}', order.status)} />
66 68 </div>
67 69 ) : (
68 70 <form onSubmit={onSubmit} className="card p-6 space-y-4 max-w-2xl">
69 71 <div className="rounded-md border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-600">
70   - Order code, output item, BOM inputs, and routing operations are read-only after creation.
  72 + {t('page.editWorkOrder.readOnlyHint')}
71 73 </div>
72 74 <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
73 75 <div>
74   - <label className="block text-sm font-medium text-slate-700">Output quantity</label>
  76 + <label className="block text-sm font-medium text-slate-700">{t('label.outputQty')}</label>
75 77 <input type="number" required min="1" step="any" value={outputQuantity}
76 78 onChange={(e) => setOutputQuantity(e.target.value)}
77 79 className="mt-1 w-full rounded-md border border-slate-300 px-3 py-2 text-sm" />
78 80 </div>
79 81 <div>
80   - <label className="block text-sm font-medium text-slate-700">Due date</label>
  82 + <label className="block text-sm font-medium text-slate-700">{t('label.dueDate')}</label>
81 83 <input type="date" value={dueDate} onChange={(e) => setDueDate(e.target.value)}
82 84 className="mt-1 w-full rounded-md border border-slate-300 px-3 py-2 text-sm" />
83 85 </div>
... ... @@ -85,7 +87,7 @@ export function EditWorkOrderPage() {
85 87 <DynamicExtFields entityName="WorkOrder" values={ext} onChange={(k, v) => setExt(prev => ({ ...prev, [k]: v }))} />
86 88 {error && <ErrorBox error={error} />}
87 89 <button type="submit" className="btn-primary" disabled={submitting}>
88   - {submitting ? 'Saving\u2026' : 'Save Changes'}
  90 + {submitting ? t('action.saving') : t('action.saveChanges')}
89 91 </button>
90 92 </form>
91 93 )}
... ...