Conversation
Reviewer's GuideUpdates the Baidu OCR sample to be fully localizable, refines the step-by-step sample code, improves toast messaging, and replaces data-annotation-based validation with localized, model-level validation logic, along with corresponding locale resource updates. Sequence diagram for localized model-level validation in BaiduOcr verify flowsequenceDiagram
actor User
participant BaiduOcr
participant ValidateForm
participant InvoiceForm
participant IStringLocalizer_BaiduOcr
User->>BaiduOcr: Submit Verify form
BaiduOcr->>ValidateForm: ValidateForm.OnValidSubmit
ValidateForm->>InvoiceForm: Validate
InvoiceForm->>IStringLocalizer_BaiduOcr: indexer InvoiceCodeRequiredError
IStringLocalizer_BaiduOcr-->>InvoiceForm: Localized message
InvoiceForm-->>ValidateForm: IEnumerable ValidationResult
alt [model is valid]
ValidateForm->>BaiduOcr: Invoke Verify(EditContext)
BaiduOcr->>BaiduOcr: OcrService.VerifyInvoiceAsync(...)
else [model has errors]
ValidateForm-->>User: Display localized validation messages
end
File-Level Changes
Assessment against linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- In
InvoiceForm,InvoiceTypeandTotalAmountare marked[NotNull]but are not validated inValidate; either add explicit validation rules for them or remove[NotNull]where the field is intended to be optional (e.g.,TotalAmount). - The placeholder for
TotalAmount(AmountPlaceHolder) suggests the field can be empty, but the[NotNull]annotation and method signature (VerifyInvoiceAsynclast parameter) imply it is required; consider aligning the validation and annotations with the intended API behavior to avoid inconsistent UX.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `InvoiceForm`, `InvoiceType` and `TotalAmount` are marked `[NotNull]` but are not validated in `Validate`; either add explicit validation rules for them or remove `[NotNull]` where the field is intended to be optional (e.g., `TotalAmount`).
- The placeholder for `TotalAmount` (`AmountPlaceHolder`) suggests the field can be empty, but the `[NotNull]` annotation and method signature (`VerifyInvoiceAsync` last parameter) imply it is required; consider aligning the validation and annotations with the intended API behavior to avoid inconsistent UX.
## Individual Comments
### Comment 1
<location path="src/BootstrapBlazor.Server/Components/Samples/BaiduOcr.razor.cs" line_range="88" />
<code_context>
}
}
- private class InvoiceForm
+ private class InvoiceForm : IValidatableObject
{
</code_context>
<issue_to_address>
**issue (complexity):** Consider extracting a reusable helper and using a data-driven loop in `InvoiceForm.Validate` to handle required-field checks and localized messages instead of repeating similar `if` blocks for each property.
You can keep the `IValidatableObject` approach and localized messages, but reduce duplication and cognitive load by extracting a small helper and using a data-driven pattern:
```csharp
private class InvoiceForm : IValidatableObject
{
[NotNull] public string? InvoiceCode { get; set; }
[NotNull] public string? InvoiceNum { get; set; }
[NotNull] public string? InvoiceDate { get; set; }
[NotNull] public string? InvoiceType { get; set; }
[NotNull] public string? CheckCode { get; set; }
[NotNull] public string? TotalAmount { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var localizer = validationContext.GetRequiredService<IStringLocalizer<BaiduOcr>>();
foreach (var result in ValidateRequired(
localizer,
(InvoiceCode, "InvoiceCodeRequiredError", nameof(InvoiceCode)),
(InvoiceNum, "InvoiceNumRequiredError", nameof(InvoiceNum)),
(InvoiceDate, "InvoiceDateRequiredError", nameof(InvoiceDate)),
(CheckCode, "CheckCodeRequiredError", nameof(CheckCode))
))
{
yield return result;
}
}
private static IEnumerable<ValidationResult> ValidateRequired(
IStringLocalizer<BaiduOcr> localizer,
params (string? Value, string ErrorKey, string MemberName)[] fields
)
{
foreach (var (value, errorKey, memberName) in fields)
{
if (string.IsNullOrWhiteSpace(value))
{
yield return new ValidationResult(
localizer[errorKey],
new[] { memberName }
);
}
}
}
}
```
This keeps the same behavior (localized messages via `IStringLocalizer<BaiduOcr>` and `IValidatableObject`) but removes the repeated `if (string.IsNullOrWhiteSpace(...)) yield return new ValidationResult(...)` blocks and centralizes the pattern in a single helper.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| } | ||
| } | ||
|
|
||
| private class InvoiceForm |
There was a problem hiding this comment.
issue (complexity): Consider extracting a reusable helper and using a data-driven loop in InvoiceForm.Validate to handle required-field checks and localized messages instead of repeating similar if blocks for each property.
You can keep the IValidatableObject approach and localized messages, but reduce duplication and cognitive load by extracting a small helper and using a data-driven pattern:
private class InvoiceForm : IValidatableObject
{
[NotNull] public string? InvoiceCode { get; set; }
[NotNull] public string? InvoiceNum { get; set; }
[NotNull] public string? InvoiceDate { get; set; }
[NotNull] public string? InvoiceType { get; set; }
[NotNull] public string? CheckCode { get; set; }
[NotNull] public string? TotalAmount { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var localizer = validationContext.GetRequiredService<IStringLocalizer<BaiduOcr>>();
foreach (var result in ValidateRequired(
localizer,
(InvoiceCode, "InvoiceCodeRequiredError", nameof(InvoiceCode)),
(InvoiceNum, "InvoiceNumRequiredError", nameof(InvoiceNum)),
(InvoiceDate, "InvoiceDateRequiredError", nameof(InvoiceDate)),
(CheckCode, "CheckCodeRequiredError", nameof(CheckCode))
))
{
yield return result;
}
}
private static IEnumerable<ValidationResult> ValidateRequired(
IStringLocalizer<BaiduOcr> localizer,
params (string? Value, string ErrorKey, string MemberName)[] fields
)
{
foreach (var (value, errorKey, memberName) in fields)
{
if (string.IsNullOrWhiteSpace(value))
{
yield return new ValidationResult(
localizer[errorKey],
new[] { memberName }
);
}
}
}
}This keeps the same behavior (localized messages via IStringLocalizer<BaiduOcr> and IValidatableObject) but removes the repeated if (string.IsNullOrWhiteSpace(...)) yield return new ValidationResult(...) blocks and centralizes the pattern in a single helper.
There was a problem hiding this comment.
Pull request overview
This PR updates the Baidu OCR sample in the server demo to fully localize its UI/UX text (labels, placeholders, toast messages, and option lists) and refresh the usage documentation flow (service registration → options configuration → injection → usage). It also replaces attribute-based required validation with IValidatableObject so validation messages can be localized via resource keys.
Changes:
- Expanded
en-US/zh-CNlocale entries for the BaiduOcr sample (labels, placeholders, option list items, toast texts). - Updated the BaiduOcr sample UI to use localized strings everywhere and added a service registration snippet.
- Updated the invoice verify form model to validate via
IValidatableObjectand use localized validation messages.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| src/BootstrapBlazor.Server/Locales/zh-CN.json | Adds BaiduOcr localized UI strings and updates usage steps for Chinese locale. |
| src/BootstrapBlazor.Server/Locales/en-US.json | Adds BaiduOcr localized UI strings and updates usage steps for English locale. |
| src/BootstrapBlazor.Server/Components/Samples/BaiduOcr.razor.cs | Localizes toast text and switches invoice form required checks to IValidatableObject with localized error keys. |
| src/BootstrapBlazor.Server/Components/Samples/BaiduOcr.razor | Uses localized labels/placeholders throughout and updates the usage steps to include service registration. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) | ||
| { | ||
| var localizer = validationContext.GetRequiredService<IStringLocalizer<BaiduOcr>>(); | ||
|
|
||
| if (string.IsNullOrWhiteSpace(InvoiceCode)) | ||
| { | ||
| yield return new ValidationResult(localizer["InvoiceCodeRequiredError"], [nameof(InvoiceCode)]); | ||
| } |
| "VatInvoiceToastSuccess": "VAT invoice recognized successfully!", | ||
| "VatInvoiceToastTitle": "VAT Invoice", | ||
| "VerifyButtonText": "Verify", | ||
| "VerifyVatInvoiceIntro": "Call the invoice verification method <code>VerifyInvoiceAsync</code> on the <code>IBaiduOcr</code> service. When the returned <code>InvoiceVerifyResult</code> has <code>Valid</code> set to <code>true</code>, the invoice is valid.", | ||
| "VerifyVatInvoiceTitle": "VAT Invoice Verification", | ||
| "VerifyVatToastTitle": "VAT Verification" |
| "VatInvoiceToastSuccess": "增值税发票识别成功!", | ||
| "VatInvoiceToastTitle": "增值税发票", | ||
| "VerifyButtonText": "验证", | ||
| "VerifyVatInvoiceIntro": "通过调用 <code>IBaiduOcr</code> 服务实例的发票验真方法 <code>VerifyInvoiceAsync</code> 返回 <code>InvoiceVerifyResult</code> 其属性 <code>Valid</code> 为 <code>true</code> 时为真", | ||
| "VerifyVatInvoiceTitle": "增值税验真" | ||
| "VerifyVatInvoiceTitle": "增值税验真", | ||
| "VerifyVatToastTitle": "增值税验真" |
| "BaiduOcrStep1": "1. Register the service", | ||
| "BaiduOcrStep1Desc": "Update the <code>appsettings.json</code> file with the following configuration. Please register on <a href=\"https://ai.baidu.com/ai-doc/index/OCR\" target=\"\">Baidu AI Open Platform</a> and apply for relevant parameter values.", |
| "BaiduOcrIntro": "使用方法", | ||
| "BaiduOcrStep1": "1. 配置 <code>BaiduOcrOption</code>", | ||
| "BaiduOcrStep1": "1. 注入服务", | ||
| "BaiduOcrStep1Desc": "更新 <code>appsettings.json</code> 文件,配置如下:相关参数值请在 <a href=\"https://ai.baidu.com/ai-doc/index/OCR\" target=\"\">百度 AI 开放平台</a> 注册后开通申请", |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8075 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 766 766
Lines 34171 34171
Branches 4700 4700
=========================================
Hits 34171 34171
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Link issues
fixes #8074
Summary By Copilot
Regression?
Risk
Verification
Packaging changes reviewed?
☑️ Self Check before Merge
Summary by Sourcery
Update the Baidu OCR sample to use fully localized UI text and validation while expanding the configuration example.
Enhancements:
Documentation: