feat: Enhance localization compliance by enforcing usage of localized keys for user-facing strings and updating related documentation

This commit is contained in:
Achintha Isuru
2026-03-10 10:00:03 -04:00
parent 316a148726
commit d6c9ed2cf3
8 changed files with 51 additions and 51 deletions

View File

@@ -58,6 +58,7 @@ and load any additional skills as needed for specific review challenges.
6. Missing tests for use cases or repositories 6. Missing tests for use cases or repositories
7. Complex BLoC without bloc_test coverage 7. Complex BLoC without bloc_test coverage
8. Test coverage below 70% for business logic 8. Test coverage below 70% for business logic
9. Hardcoded user-facing strings — must use `core_localization` (Slang) via `t.<section>.<key>`. All `Text('...')` with literal English/Spanish strings in presentation layer must be replaced with localized keys
### MODERATE (Request Fix, can be deferred with justification): ### MODERATE (Request Fix, can be deferred with justification):
1. Missing doc comments on public APIs 1. Missing doc comments on public APIs
@@ -103,7 +104,7 @@ Verify:
- Business logic resides exclusively in use cases - Business logic resides exclusively in use cases
- Entities are in domain, models in data, widgets in presentation - Entities are in domain, models in data, widgets in presentation
### Step 3: Design System Compliance ### Step 3: Design System & Localization Compliance
```bash ```bash
# Hardcoded colors # Hardcoded colors
@@ -117,9 +118,22 @@ grep -rn -E "EdgeInsets\.(all|symmetric|only)\(" apps/mobile/apps/*/lib/features
# Direct icon imports # Direct icon imports
grep -rn "^import.*icons" apps/mobile/apps/*/lib/features/ grep -rn "^import.*icons" apps/mobile/apps/*/lib/features/
# Hardcoded user-facing strings (look for Text('...') with literal strings)
grep -rn "Text(['\"]" apps/mobile/packages/features/
# Also check for hardcoded strings in SnackBar, AlertDialog, AppBar title, etc.
grep -rn "title: ['\"]" apps/mobile/packages/features/
grep -rn "label: ['\"]" apps/mobile/packages/features/
grep -rn "hintText: ['\"]" apps/mobile/packages/features/
``` ```
All styling must come from the design system. No exceptions. All styling must come from the design system. All user-facing strings must come from `core_localization` via Slang (`t.<section>.<key>`). No exceptions.
**Localization rules:**
- Strings defined in `packages/core_localization/lib/src/l10n/en.i18n.json` and `es.i18n.json`
- Accessed via `t.<section>.<key>` (e.g., `t.client_create_order.review.invalid_arguments`)
- Both `en` and `es` JSON files must be updated together
- Regenerate with `dart run slang` from `packages/core_localization/` directory
### Step 4: State Management Review ### Step 4: State Management Review
For every BLoC in changed files, verify: For every BLoC in changed files, verify:

View File

@@ -266,11 +266,29 @@ design_system/
- Export `TranslationProvider` for `context.strings` access - Export `TranslationProvider` for `context.strings` access
- Map domain failures to localized error messages via `ErrorTranslator` - Map domain failures to localized error messages via `ErrorTranslator`
**String Definition:**
- Strings are defined in `packages/core_localization/lib/src/l10n/en.i18n.json` (English) and `es.i18n.json` (Spanish)
- Both files MUST be updated together when adding/modifying strings
- Generated output: `strings.g.dart`, `strings_en.g.dart`, `strings_es.g.dart`
- Regenerate with: `cd packages/core_localization && dart run slang`
**Feature Integration:** **Feature Integration:**
```dart ```dart
// Features access strings // ✅ CORRECT: Access via Slang's global `t` accessor
Text(context.strings.loginButton) import 'package:core_localization/core_localization.dart';
Text(t.client_create_order.review.invalid_arguments)
Text(t.errors.order.creation_failed)
// ❌ FORBIDDEN: Hardcoded user-facing strings
Text('Invalid review arguments') // Must use localized key
Text('Order created!') // Must use localized key
```
**RESTRICTION:** ALL user-facing strings in the presentation layer (Text widgets, SnackBars, AppBar titles, hints, labels, error messages, dialogs) MUST use localized keys via `t.<section>.<key>`. No hardcoded English or Spanish strings.
**BLoC Error Flow:**
```dart
// BLoCs emit domain failures (not strings) // BLoCs emit domain failures (not strings)
emit(AuthError(InvalidCredentialsFailure())); emit(AuthError(InvalidCredentialsFailure()));
@@ -879,6 +897,11 @@ Navigator.push(context, MaterialPageRoute(...)); // ← Use Modular
Modular.to.navigate('/profile'); // ← Use safe extensions Modular.to.navigate('/profile'); // ← Use safe extensions
``` ```
**Hardcoded user-facing strings**
```dart
Text('Order created successfully!'); // ← Use t.section.key from core_localization
```
## Summary ## Summary
The architecture enforces: The architecture enforces:

View File

@@ -1,33 +0,0 @@
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
/// Displays the "Review & Submit" title and subtitle at the top of the
/// review order page.
class ReviewOrderHeader extends StatelessWidget {
const ReviewOrderHeader({super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(
left: UiConstants.space6,
right: UiConstants.space6,
top: UiConstants.space4,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Review & Submit',
style: UiTypography.headline2m,
),
const SizedBox(height: UiConstants.space1),
Text(
'Confirm details before posting',
style: UiTypography.body2r.textSecondary,
),
],
),
);
}
}

View File

@@ -19,18 +19,18 @@ class ReviewOrderInfoRow extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
spacing: UiConstants.space2,
children: <Widget>[ children: <Widget>[
Flexible( Flexible(
child: Text( child: Text(
label, label,
style: UiTypography.body3r.textSecondary, style: UiTypography.body2r.textSecondary,
), ),
), ),
const SizedBox(width: UiConstants.space3),
Flexible( Flexible(
child: Text( child: Text(
value, value,
style: UiTypography.body3m, style: UiTypography.body2m,
textAlign: TextAlign.end, textAlign: TextAlign.end,
), ),
), ),

View File

@@ -26,7 +26,7 @@ class ReviewOrderPositionsCard extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: UiColors.white, color: UiColors.white,
borderRadius: UiConstants.radiusXl, borderRadius: UiConstants.radiusXl,
border: Border.all(color: UiColors.border), border: Border.all(color: UiColors.border, width: 0.5),
), ),
padding: const EdgeInsets.all(UiConstants.space4), padding: const EdgeInsets.all(UiConstants.space4),
child: Column( child: Column(

View File

@@ -23,7 +23,7 @@ class ReviewOrderSectionCard extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: UiColors.white, color: UiColors.white,
borderRadius: UiConstants.radiusXl, borderRadius: UiConstants.radiusXl,
border: Border.all(color: UiColors.border), border: Border.all(color: UiColors.border, width: 0.5),
), ),
padding: const EdgeInsets.all(UiConstants.space4), padding: const EdgeInsets.all(UiConstants.space4),
child: Column( child: Column(
@@ -39,10 +39,7 @@ class ReviewOrderSectionCard extends StatelessWidget {
if (onEdit != null) if (onEdit != null)
GestureDetector( GestureDetector(
onTap: onEdit, onTap: onEdit,
child: Text( child: Text('Edit', style: UiTypography.body3m.primary),
'Edit',
style: UiTypography.body3m.primary,
),
), ),
], ],
), ),

View File

@@ -2,7 +2,6 @@ import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'review_order_action_bar.dart'; import 'review_order_action_bar.dart';
import 'review_order_basics_card.dart'; import 'review_order_basics_card.dart';
import 'review_order_header.dart';
import 'review_order_positions_card.dart'; import 'review_order_positions_card.dart';
import 'review_order_total_banner.dart'; import 'review_order_total_banner.dart';
@@ -56,10 +55,11 @@ class ReviewOrderView extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: UiColors.bgMenu,
appBar: UiAppBar( appBar: UiAppBar(
showBackButton: true, showBackButton: true,
onLeadingPressed: onBack, onLeadingPressed: onBack,
title: 'Review & Submit',
subtitle: 'Confirm details before posting',
), ),
body: Column( body: Column(
children: <Widget>[ children: <Widget>[
@@ -68,7 +68,6 @@ class ReviewOrderView extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
const ReviewOrderHeader(),
Padding( Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: UiConstants.space6, horizontal: UiConstants.space6,

View File

@@ -1,5 +1,5 @@
specVersion: "v1" specVersion: "v1"
serviceId: "krow-workforce-db-validation" serviceId: "krow-workforce-db"
location: "us-central1" location: "us-central1"
schema: schema:
source: "./schema" source: "./schema"
@@ -7,7 +7,7 @@ schema:
postgresql: postgresql:
database: "krow_db" database: "krow_db"
cloudSql: cloudSql:
instanceId: "krow-sql-validation" instanceId: "krow-sql"
# schemaValidation: "STRICT" # STRICT mode makes Postgres schema match Data Connect exactly. # schemaValidation: "STRICT" # STRICT mode makes Postgres schema match Data Connect exactly.
# schemaValidation: "COMPATIBLE" # COMPATIBLE mode makes Postgres schema compatible with Data Connect. # schemaValidation: "COMPATIBLE" # COMPATIBLE mode makes Postgres schema compatible with Data Connect.
connectorDirs: ["./connector"] connectorDirs: ["./connector"]