import { EmailError } from '../map-error.js' const COPY = Object.freeze({ zh: { purposes: { order_paid: ['订单已完成', '我们已收到您的付款。'], subscription_active: ['订阅已生效', '您的 VOKO 订阅现已生效。'], subscription_canceled: ['订阅已取消', '您的 VOKO 订阅已取消。'], order_refunded: ['订单已退款', '您的订单退款已处理。'], order_disputed: ['订单正在审核', '您的订单存在争议,目前正在审核。'], }, order: '订单编号', product: '商品', amount: '金额', status: '状态', footer: '感谢您使用 VOKO。', statuses: { pending: '待支付', paid: '已支付', refunded: '已退款', disputed: '争议处理中' }, }, en: { purposes: { order_paid: ['Your order is complete', 'We have received your payment.'], subscription_active: ['Your subscription is active', 'Your VOKO subscription is now active.'], subscription_canceled: ['Your subscription was canceled', 'Your VOKO subscription has been canceled.'], order_refunded: ['Your order was refunded', 'Your order refund has been processed.'], order_disputed: ['Your order is under review', 'A dispute was opened for your order and is now under review.'], }, order: 'Order', product: 'Product', amount: 'Amount', status: 'Status', footer: 'Thank you for using VOKO.', statuses: { pending: 'Pending', paid: 'Paid', refunded: 'Refunded', disputed: 'Under review' }, }, ja: { purposes: { order_paid: ['ご注文が完了しました', 'お支払いを確認しました。'], subscription_active: ['サブスクリプションが有効になりました', 'VOKOのサブスクリプションをご利用いただけます。'], subscription_canceled: ['サブスクリプションが解約されました', 'VOKOのサブスクリプションが解約されました。'], order_refunded: ['ご注文の返金が完了しました', 'ご注文の返金手続きが完了しました。'], order_disputed: ['ご注文を確認中です', 'ご注文に対する異議申し立てがあり、現在確認中です。'], }, order: '注文番号', product: '商品', amount: '金額', status: 'ステータス', footer: 'VOKOをご利用いただきありがとうございます。', statuses: { pending: '支払い待ち', paid: '支払い済み', refunded: '返金済み', disputed: '確認中' }, }, ko: { purposes: { order_paid: ['주문이 완료되었습니다', '결제가 확인되었습니다.'], subscription_active: ['구독이 활성화되었습니다', 'VOKO 구독이 활성화되었습니다.'], subscription_canceled: ['구독이 취소되었습니다', 'VOKO 구독이 취소되었습니다.'], order_refunded: ['주문이 환불되었습니다', '주문 환불 처리가 완료되었습니다.'], order_disputed: ['주문을 검토 중입니다', '주문에 대한 이의 제기가 접수되어 현재 검토 중입니다.'], }, order: '주문 번호', product: '상품', amount: '금액', status: '상태', footer: 'VOKO를 이용해 주셔서 감사합니다.', statuses: { pending: '결제 대기', paid: '결제 완료', refunded: '환불 완료', disputed: '검토 중' }, }, es: { purposes: { order_paid: ['Tu pedido se ha completado', 'Hemos recibido tu pago.'], subscription_active: ['Tu suscripción está activa', 'Tu suscripción a VOKO ya está activa.'], subscription_canceled: ['Tu suscripción fue cancelada', 'Tu suscripción a VOKO ha sido cancelada.'], order_refunded: ['Tu pedido fue reembolsado', 'El reembolso de tu pedido ha sido procesado.'], order_disputed: ['Tu pedido está en revisión', 'Se ha abierto una disputa sobre tu pedido y está en revisión.'], }, order: 'Pedido', product: 'Producto', amount: 'Importe', status: 'Estado', footer: 'Gracias por usar VOKO.', statuses: { pending: 'Pendiente', paid: 'Pagado', refunded: 'Reembolsado', disputed: 'En revisión' }, }, pt: { purposes: { order_paid: ['Seu pedido foi concluído', 'Recebemos seu pagamento.'], subscription_active: ['Sua assinatura está ativa', 'Sua assinatura do VOKO está ativa.'], subscription_canceled: ['Sua assinatura foi cancelada', 'Sua assinatura do VOKO foi cancelada.'], order_refunded: ['Seu pedido foi reembolsado', 'O reembolso do seu pedido foi processado.'], order_disputed: ['Seu pedido está em análise', 'Uma contestação foi aberta para seu pedido, que agora está em análise.'], }, order: 'Pedido', product: 'Produto', amount: 'Valor', status: 'Status', footer: 'Obrigado por usar o VOKO.', statuses: { pending: 'Pendente', paid: 'Pago', refunded: 'Reembolsado', disputed: 'Em análise' }, }, }) export function render(data) { if (!data || typeof data !== 'object') fail('data is required') const copy = COPY[data.locale] if (!copy) fail(`unsupported locale: ${String(data.locale)}`) const purposeCopy = copy.purposes[data.purpose] if (!purposeCopy) fail(`unsupported purpose: ${String(data.purpose)}`) const orderId = requiredText(data.orderId, 'orderId') const productId = requiredText(data.productId, 'productId') const status = copy.statuses[data.status] if (!status) fail(`unsupported status: ${String(data.status)}`) const amount = optionalText(data.amount) const [subject, intro] = purposeCopy const details = [ `${copy.order}: ${orderId}`, `${copy.product}: ${productId}`, amount ? `${copy.amount}: ${amount}` : null, `${copy.status}: ${status}`, ].filter(Boolean) const text = [subject, '', intro, '', ...details, '', copy.footer].join('\n') const html = [ '
', `${escapeHtml(intro)}
`, ...details.map(detail => `${escapeHtml(detail)}
`), `${escapeHtml(copy.footer)}
`, '', ].join('') return { subject, html, text } } function requiredText(value, field) { if (typeof value === 'string' && value.trim()) return value.trim() fail(`missing field "${field}"`) } function optionalText(value) { if (value === undefined || value === null || value === '') return '' return requiredText(value, 'amount') } function fail(message) { throw new EmailError({ provider: 'template', reason: 'badTemplate', retryable: false, message: `order-notice: ${message}` }) } function escapeHtml(value) { return String(value) .replaceAll('&', '&') .replaceAll('<', '<') .replaceAll('>', '>') .replaceAll('"', '"') .replaceAll("'", ''') }