Summary

Flow Mobile supports three languages: English (base), Italian, Spanish. All user-facing strings are managed via Flutter’s ARB-based localization system.


Architecture

ComponentPath
ARB source fileslib/l10n/app_en.arb, app_it.arb, app_es.arb
Generated Dart fileslib/l10n/app_localizations*.dart (auto-generated)
Configl10n.yaml (synthetic-package: false)
Import pathpackage:flow/l10n/app_localizations.dart

The package is named flow (renamed from flow_app). The import is package:flow/l10n/... — not package:flow_app/l10n/....

synthetic-package: false means generated files live inside lib/l10n/ rather than a synthetic package. Never use flutter_gen/gen_l10n/ imports.


Usage Pattern

import 'package:flow/l10n/app_localizations.dart';
 
// In a build method:
final l10n = AppLocalizations.of(context)!;
Text(l10n.someKey);
 
// With parameters:
Text(l10n.photoUploadError(e.toString()));
Text(l10n.participantsCount(count.toString()));

Adding New Strings

  1. Add key + value to app_en.arb (English is the template).
  2. Add the same key to app_it.arb and app_es.arb with translations.
  3. For parameterized strings, add an @key metadata block:
"photoUploadError": "Error uploading photo: {error}",
"@photoUploadError": {
  "placeholders": {
    "error": { "type": "String" }
  }
}
  1. Regenerate:
flutter pub get
# or:
flutter gen-l10n
  1. Use in Dart via AppLocalizations.of(context)!.myKey.

Key Conventions

PatternExampleWhen
screenActioneditProfile, saveChangesButtons, titles
sectionNamesectionPersonalInfo, sectionVibeCheckSection headers
wizardStepTitlewizardWelcomeTitle, wizardNameSubtitleRegistration wizard
wizardValidation*wizardValidationEmailRequiredInline wizard error messages
errorDescriptionphotoUploadError, cannotLoadMessagesError messages
labelNameemailLabel, passwordLabel, bioLabelForm field labels

const Propagation Rule

When replacing const Text('literal') with Text(l10n.key), remove const from the Text. Keep const on: TextStyle, Icon, SizedBox, and any ancestor that doesn’t depend on the runtime value.


Locale-Aware Dates

Use the intl package — not hardcoded arrays:

import 'package:intl/intl.dart';
 
final locale = Localizations.localeOf(context).toString();
final monthName = DateFormat('MMMM', locale).format(DateTime(2024, month));

Used in FlowDateWheelPicker and the feed screen’s showDatePicker.


Strings Intentionally NOT Localized

  • Vibe filter labels ("Tutto", "Consigliati" etc.) — serve as DB tag keys; localizing would break filter logic.
  • searchFieldLabel in SearchDelegate subclasses — getter has no BuildContext.
  • Brand names (Instagram, TikTok, Flow) — kept as-is.

Duplicate-Key Detection

Flutter’s ARB parser silently keeps the last occurrence of a duplicate key. Run this before any merge:

python -c "import re; from collections import Counter; \
  print(Counter(re.findall(r'^\s*\"([a-zA-Z]\w*)\"\s*:', open('lib/l10n/app_en.arb').read(), re.M)).most_common(10))"

Screens Fully Localized

Auth: registration_wizard_screen, forgot_password_screen, welcome_screen, login_screen Feed: feed_screen Events: event_discovery_screen, event_details_screen, events_screen Messaging: chat_screen, chat_details_screen, chats_screen, message_requests_screen, new_chat_screen Profile: profile_screen, edit_profile_screen, profile_setup_screen Settings: settings_screen, privacy_settings_screen Social: friends_screen Search: search_screen Notifications: notifications_screen Shared widgets: error_reporter_overlay, empty_state_widget, error_widget, loading_widgets, flow_date_wheel_picker, minimal_event_card, product_checkout_sheet, squad_bento_section, squad_detail_sheet


Key Inventory — Added May 2026

Added during event-details v3 refactor (2026-05-07, see feat-event-details-v3):

KeyWhere used
liveTonight, tomorrowNightHero live-chip (date-aware)
attendeesLabel, likesLabelStats strip
ratingSeriesLabel, ratingVenueLabelStats strip — context-aware rating row
venueLabel, seriesLabelVenue + series breadcrumb headers
ticketSoldOut, ticketSoldOutShortSold-out indicator + button
ticketLowStockUrgent (placeholder remaining: int)“Hurry up! N spots left”
ticketNotOnSaleSale window not yet open
lineupGeneralArea, lineupUnknownAreaLineup grouping fallbacks
crewsHeader, crewsSeeAll, crewsSeeAllWithMore (placeholder extra: int), crewsEmptyTitle, crewsEmptySubtitleCrews section
bottomBarAttendingLabel, bottomBarAttendingHeadline, bottomBarFromLabelBottom action bar states

Added during auth-screen deep-rework (edit/mobile-audit-ux-polish, commit 841ec58):

KeyScreen
continueWithFacebookLogin social divider
socialSignInComingSoonLogin / forgot social icons
orContinueWithLogin / forgot divider label
byUsingYouAcceptWelcome terms line
welcomeRegisterWelcome footer CTA
welcomeLoginWelcome footer CTA
messagePublic profile screen
nextEventsTabPublic profile screen
pastEventsTabPublic profile screen

Previously added (April 2026 design cleanup):

welcomeHeadline, welcomeCarouselLine1–4, continueWithApple, continueWithGoogle, appleSignInComingSoon, googleSignInComingSoon, signInWithEmail

Wizard validation keys (full list in feat-registration-wizard-v2):

wizardValidationFirstNameRequired, wizardValidationAgeRestriction, wizardValidationUsernameRequired, wizardValidationUsernameFormat, wizardValidationUsernameTaken, wizardValidationEmailRequired, wizardValidationEmailFormat, wizardValidationPasswordTooShort, wizardValidationBusinessNameRequired, wizardValidationBusinessCategoryRequired, wizardValidationStageNameRequired, wizardValidationLocationRequired, wizardValidationEmailTaken, dateInputDay, dateInputMonth, dateInputYear, dateInputModeKeyboard, dateInputModeWheel


auth-screens — auth-specific l10n keys grouped by screen feat-registration-wizard-v2 — wizard validation keys