Full app localization: English + Korean, behind a feature flag - #308
Full app localization: English + Korean, behind a feature flag#308KamaIOps wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 50655d3611
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| "receivePreviewShieldedRenew": "받기 페이지를 열거나 갱신 버튼을\n누를 때마다 새로운 Zcash 쉴드\n주소가 생성됩니다.", | ||
| "receivePreviewShieldedDiversified": "새 주소는 모두 같은 키에서 파생된\n다변화 주소입니다.\n모두 같은 지갑으로 입금됩니다.", | ||
| "passwordTooShort": "비밀번호는 최소 {min}자 이상이어야 합니다.", | ||
| "passwordAsciiOnly": "영문자, 숫자, 기호만 사용하세요.", |
There was a problem hiding this comment.
Keep the password charset warning literal
Under the Wallet Password Policy in AGENTS.md, the charset validation message must stay exactly Use only English letters, numbers, and symbols.. With Korean selected, every screen using validateWalletPasswordLocalized now shows this translated value for non-ASCII passwords, so the required support/security copy no longer matches the documented invariant; keep this key's displayed value literal across locales or avoid localizing this specific validation message.
Useful? React with 👍 / 👎.
| /// OS locale when no preference is stored, clamped to the supported set | ||
| /// (English fallback). | ||
| Locale resolveAppLocale(Locale? preference) { | ||
| final locale = preference ?? PlatformDispatcher.instance.locale; |
There was a problem hiding this comment.
Resolve provider locale from the full OS list
When no language preference is saved, MaterialApp.locale is null and Flutter resolves from the full preferred OS locale list, but this provider-side resolver only checks the primary PlatformDispatcher.instance.locale. For users whose primary OS language is unsupported but Korean is later in their preferred languages, widget text can render Korean while provider/service messages from appLocalizationsProvider fall back to English, producing mixed-language errors and status text; resolve against PlatformDispatcher.instance.locales using the same supported-locale matching.
Useful? React with 👍 / 👎.
50655d3 to
f1be969
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f1be9697f1
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| <key>CFBundleLocalizations</key> | ||
| <array> | ||
| <string>en</string> | ||
| <string>ko</string> |
There was a problem hiding this comment.
Add Korean InfoPlist strings for native prompts
Adding ko here advertises a Korean native localization, but the camera and Face ID permission prompts still come from the English NSCameraUsageDescription / NSFaceIDUsageDescription values because there is no ko.lproj/InfoPlist.strings under ios/Runner (and the same search shows only Base.lproj under macOS). In the QR-scan or biometric flows, Korean users will see English OS dialogs while the Flutter UI is Korean; add localized InfoPlist strings before declaring Korean support.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Addressed — ios/Runner/en.lproj/InfoPlist.strings, ios/Runner/ko.lproj/InfoPlist.strings, and the macOS equivalents are in this branch (wired into both Runner.xcodeproj variant groups, ko added to knownRegions). Verified the built app bundles contain ko.lproj/InfoPlist.strings on both platforms.
f1be969 to
e7047e3
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e7047e32ef
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| return ref | ||
| .read(deviceOwnerAuthProvider) | ||
| .verify(reason: kWalletResetDeviceAuthReason); | ||
| .verify(reason: reason ?? kWalletResetDeviceAuthReason); |
There was a problem hiding this comment.
Pass the localized reset auth reason
When the locale is Korean and a wallet reset reaches the OS device-owner prompt, both reset flows still call verifyDeviceOwnerForWalletReset(ref) without a reason, so this fallback sends the hardcoded English Confirm reset Vizor even though walletResetDeviceAuthReason was added to the ARB files. Please thread the localized reason into those calls; otherwise the destructive reset confirmation remains outside the language feature.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Addressed — both reset flows now pass a localized reason: forgot_passcode_sheet.dart threads deviceAuthConfirmReset via appLocalizationsProvider, and lost_password_screen.dart passes it from AppLocalizations.of(context). The unused walletResetDeviceAuthReason key was removed.
|
@codex review |
e7047e3 to
101dd46
Compare
…flag Migrate every user-facing string across desktop and mobile to Flutter gen-l10n (lib/l10n/app_en.arb + app_ko.arb, ~1,160 keys) and ship a full Korean translation. English ARB values are byte-identical to the previous hardcoded literals, so English builds render exactly as before. Language selection: - Settings gains a Language option — System (Auto) / English / 한국어 — on desktop (modal) and mobile (sheet). - With no stored preference the app follows the OS locale, clamped to supportedLocales with an English fallback; a saved choice always wins. - localeProvider gains clearToSystem(); a context-free appLocalizationsProvider serves providers and services. Feature flag (kill switch): - VIZOR_LANGUAGE_ENABLED (compile-time dart-define, default true). Building with --dart-define=VIZOR_LANGUAGE_ENABLED=false pins the app to English, ignores stored/OS locale, and hides the Language rows — restoring the pre-i18n behavior verbatim without a revert. The const flag is tree-shaken from release builds. Localization mechanics: - Screens use AppLocalizations.of(context); context-free helpers and friendly-error mappers take an AppLocalizations parameter; Riverpod providers read appLocalizationsProvider (test-safe fallback). - Dates use intl DateFormat guarded by intlSafeLocale(), with locale-aware day/month ordering; hardcoded month tables removed. - Label-text sniffing replaced by typed kinds: SwapStatusDetailRowKind on swap status rows and AddressFormatIssueKind on address findings, so filtering/ordering/tooltips no longer parse English labels. - Rust-thrown error strings remain English as mapper inputs; only mapper output is localized. Persisted data (account names, swap records) stays English. Tooling and tests: - Widgetbook gains a LocalizationAddon with a locale switcher. - ~95 test harnesses receive AppLocalizations delegates (MaterialApp, MaterialApp.router, and bare AppTheme wrappers). - CFBundleLocalizations (en, ko) added to iOS and macOS Info.plists. - Fixed-height cards on the unlock/set-password/intro screens gain 8px headroom so taller Korean type fits. Verification: flutter analyze clean; desktop lane 1422 passed / 1 failed (receive_use_cases_test, pre-existing on main); mobile lane 325 passed / 2 failed (mobile_routes_test, mobile_receive_use_cases_test, both pre-existing on main). Manually verified on macOS: language switching, follow-OS resolution, onboarding/create/import flows, Keystone connect, send end-to-end, activity and swap surfaces in Korean.
101dd46 to
7295b2b
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7295b2b76a
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| <key>CFBundleLocalizations</key> | ||
| <array> | ||
| <string>en</string> | ||
| <string>ko</string> | ||
| </array> |
There was a problem hiding this comment.
Honor the language kill switch for native localizations
When a build is launched with VIZOR_LANGUAGE_ENABLED=false, the Dart app is pinned to English, but this bundle still advertises Korean as a supported native localization (and the same pattern is added on macOS). On a Korean-system device, iOS will still use the new ko.lproj/InfoPlist.strings for camera/Face ID permission prompts, so the rollout kill switch no longer restores the pre-i18n English-only behavior and users can see mixed-language system prompts while the app UI is forced to English.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Intended scope: the kill switch is a compile-time Dart define and governs the Flutter layer (app strings, Language UI, locale resolution) — it exists to roll back app-string regressions. The InfoPlist strings are static bundle resources rendered by the OS in the device language, which is standard iOS/macOS behavior for any app that ships localizations; they can't observe a dart-define without custom build-phase scripting, which seems disproportionate for two static permission sentences with no regression surface. Documented this scope in the PR description. If the team prefers, a follow-up could gate the lproj resources per build flavor, but I'd argue an OS prompt in the device language alongside an English-pinned app is the platform-correct state, not a regression.
Re-apply localization over main's redesigns: mobile send status screen, Keystone mobile signing refresh (Step 1/2 / 2/2 full-screen scanner), method selection (wallet-link card), address-book contact name surfaces, and swap review/composer updates. Adds en/ko keys for the new copy and threads l10n through the new call sites.
There was a problem hiding this comment.
💡 Codex Review
When Korean is selected, this Settings row still shows a hard-coded English label and opens /settings/link-mobile; I checked lib/src/features/wallet_link and it has no AppLocalizations usage, with the linked screen still rendering hard-coded English titles/buttons such as Link Vizor Mobile and Regenerate. Because this PR enables Korean for the app, desktop users can enter an entire mixed-language wallet-link flow from Korean Settings, so localize this row and the wallet-link screens or hide the entry until they are localized.
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Full app localization: English + Korean, behind a feature flag
What this does
Migrates every user-facing string across desktop and mobile to Flutter gen-l10n (
lib/l10n/app_en.arb+app_ko.arb, ~1,260 keys) and ships a complete Korean translation, with a Language setting and follow-OS locale resolution.English builds are unaffected: every English ARB value is byte-identical to the previous hardcoded literal, so the rendered UI is string-for-string the same as before this PR. The existing
find.text()test assertions (1,400+) pass unchanged and act as regression coverage for that guarantee.Language selection
supportedLocaleswith an English fallback. A saved choice always wins.localeProvider(+clearToSystem()) and a context-freeappLocalizationsProviderfor providers/services.Kill switch
VIZOR_LANGUAGE_ENABLED(compile-time dart-define, default: enabled).Disabled = locale pinned to English (OS locale and stored preference ignored) + Language rows/modal hidden — i.e. the exact pre-PR behavior, restorable per build without reverting this PR. The const flag tree-shakes the dead branch out of release builds.
Scope: the flag governs the Flutter layer (app strings, Language UI, locale resolution). The native
InfoPlist.stringspermission prompts are static bundle resources that follow the device language — standard OS behavior for any localized app — and are not affected by the flag.Implementation notes
AppLocalizations.of(context); context-free helpers/error mappers take anAppLocalizationsparameter; Riverpod providers readappLocalizationsProvider.intlDateFormatwith anintlSafeLocale()guard (pure-Dart tests never initialize locale data) and locale-aware day/month ordering; the hardcoded English month tables are gone.SwapStatusDetailRowKindon swap status detail rows andAddressFormatIssueKindon address-format findings, so row filtering/ordering/tooltips no longer parse English label text. A final sweep converted the last three label-sniffing sites (activity-feed routine-status detection, the swap fee-divider placement, and the swap status tab keys) to localized comparisons / kind checks — these rendered wrong in Korean otherwise.nextAction) stays English.test/l10n/arb_parity_test.dartfails the build if an English key ships without a Korean translation (gen-l10n falls back silently otherwise) or if Korean uses an undeclared placeholder.LocalizationAddon(locale switcher in the sidebar).CFBundleLocalizations(en, ko) added to the iOS/macOS Info.plists. No Rust changes.Coverage notes
Info.plistpermission prompts. Candidate follow-up.Verification
fvm flutter analyze: clean.receive_use_cases_test— pre-existing onmain).mobile_routes_test,mobile_receive_use_cases_test— pre-existing onmain).Reviewer pointers
lib/src/providers/locale_provider.dart,lib/app.dart, the kind-enum refactors inlib/src/features/swap/models/, andlib/src/core/formatting/date_format.dart.