← Back to Blog

Flutter Container Localization: Versatile Styling for Multilingual UIs

fluttercontainerlayoutstylinglocalizationresponsive

Flutter Container Localization: Versatile Styling for Multilingual UIs

Container is one of Flutter's most versatile widgets, combining sizing, padding, margins, decoration, and transformations in a single widget. In multilingual applications, Container provides the flexibility to create styled layouts that adapt to varying content lengths and text directions.

Understanding Container in Localization Context

Container wraps multiple layout behaviors into one convenient widget. For multilingual apps, this creates:

  • Consistent styling across LTR and RTL layouts
  • Flexible sizing that accommodates text expansion
  • Decoration that respects text direction
  • Combined padding and margin control

Why Container Matters for Multilingual Apps

Container's versatility provides:

  • Unified styling: One widget for complex visual requirements
  • Direction awareness: Alignment and decoration respect RTL
  • Content adaptation: Sizing can flex with text length
  • Clean code: Fewer nested widgets for common patterns

Basic Container Implementation

import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

class LocalizedContainerExample extends StatelessWidget {
  const LocalizedContainerExample({super.key});

  @override
  Widget build(BuildContext context) {
    final l10n = AppLocalizations.of(context)!;

    return Container(
      padding: const EdgeInsets.all(16),
      margin: const EdgeInsets.all(8),
      decoration: BoxDecoration(
        color: Theme.of(context).colorScheme.primaryContainer,
        borderRadius: BorderRadius.circular(12),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withOpacity(0.1),
            blurRadius: 8,
            offset: const Offset(0, 2),
          ),
        ],
      ),
      child: Text(
        l10n.containerContent,
        style: Theme.of(context).textTheme.bodyLarge,
      ),
    );
  }
}

Direction-Aware Container Patterns

RTL-Safe Container with Directional Padding

class DirectionalContainer extends StatelessWidget {
  final Widget child;
  final EdgeInsetsDirectional padding;
  final BoxDecoration? decoration;

  const DirectionalContainer({
    super.key,
    required this.child,
    this.padding = const EdgeInsetsDirectional.all(16),
    this.decoration,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: padding,
      decoration: decoration,
      child: child,
    );
  }
}

// Usage with localized content
class DirectionalCardExample extends StatelessWidget {
  const DirectionalCardExample({super.key});

  @override
  Widget build(BuildContext context) {
    final l10n = AppLocalizations.of(context)!;

    return DirectionalContainer(
      padding: const EdgeInsetsDirectional.only(
        start: 16,
        end: 24,
        top: 12,
        bottom: 12,
      ),
      decoration: BoxDecoration(
        color: Theme.of(context).colorScheme.surface,
        borderRadius: BorderRadius.circular(8),
        border: Border.all(
          color: Theme.of(context).colorScheme.outline.withOpacity(0.2),
        ),
      ),
      child: Row(
        children: [
          const Icon(Icons.info_outline),
          const SizedBox(width: 12),
          Expanded(
            child: Text(l10n.infoMessage),
          ),
        ],
      ),
    );
  }
}

Alignment-Aware Container

class LocalizedAlignedContainer extends StatelessWidget {
  final Widget child;
  final AlignmentDirectional alignment;

  const LocalizedAlignedContainer({
    super.key,
    required this.child,
    this.alignment = AlignmentDirectional.centerStart,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: alignment,
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: Theme.of(context).colorScheme.surfaceContainerHighest,
        borderRadius: BorderRadius.circular(8),
      ),
      child: child,
    );
  }
}

// Usage
class AlignmentExample extends StatelessWidget {
  const AlignmentExample({super.key});

  @override
  Widget build(BuildContext context) {
    final l10n = AppLocalizations.of(context)!;

    return Column(
      children: [
        LocalizedAlignedContainer(
          alignment: AlignmentDirectional.centerStart,
          child: Text(l10n.startAlignedText),
        ),
        const SizedBox(height: 16),
        LocalizedAlignedContainer(
          alignment: AlignmentDirectional.centerEnd,
          child: Text(l10n.endAlignedText),
        ),
      ],
    );
  }
}

Styled Card Containers

Localized Info Card

class LocalizedInfoCard extends StatelessWidget {
  final IconData icon;
  final String title;
  final String description;
  final Color? backgroundColor;

  const LocalizedInfoCard({
    super.key,
    required this.icon,
    required this.title,
    required this.description,
    this.backgroundColor,
  });

  @override
  Widget build(BuildContext context) {
    final bgColor = backgroundColor ??
        Theme.of(context).colorScheme.primaryContainer;

    return Container(
      width: double.infinity,
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: bgColor,
        borderRadius: BorderRadius.circular(16),
      ),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            width: 48,
            height: 48,
            decoration: BoxDecoration(
              color: Theme.of(context).colorScheme.primary,
              borderRadius: BorderRadius.circular(12),
            ),
            child: Icon(
              icon,
              color: Theme.of(context).colorScheme.onPrimary,
            ),
          ),
          const SizedBox(width: 16),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  title,
                  style: Theme.of(context).textTheme.titleMedium?.copyWith(
                    fontWeight: FontWeight.bold,
                  ),
                ),
                const SizedBox(height: 8),
                Text(
                  description,
                  style: Theme.of(context).textTheme.bodyMedium?.copyWith(
                    color: Theme.of(context).colorScheme.onSurfaceVariant,
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

// Usage
class InfoCardsExample extends StatelessWidget {
  const InfoCardsExample({super.key});

  @override
  Widget build(BuildContext context) {
    final l10n = AppLocalizations.of(context)!;

    return Column(
      children: [
        LocalizedInfoCard(
          icon: Icons.lightbulb,
          title: l10n.tipTitle,
          description: l10n.tipDescription,
        ),
        const SizedBox(height: 16),
        LocalizedInfoCard(
          icon: Icons.warning,
          title: l10n.warningTitle,
          description: l10n.warningDescription,
          backgroundColor: Theme.of(context).colorScheme.errorContainer,
        ),
      ],
    );
  }
}

Status Badge Container

class LocalizedStatusBadge extends StatelessWidget {
  final String label;
  final StatusType status;

  const LocalizedStatusBadge({
    super.key,
    required this.label,
    required this.status,
  });

  @override
  Widget build(BuildContext context) {
    final colors = _getStatusColors(context);

    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
      decoration: BoxDecoration(
        color: colors.background,
        borderRadius: BorderRadius.circular(16),
        border: Border.all(color: colors.border),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Container(
            width: 8,
            height: 8,
            decoration: BoxDecoration(
              color: colors.indicator,
              shape: BoxShape.circle,
            ),
          ),
          const SizedBox(width: 8),
          Text(
            label,
            style: Theme.of(context).textTheme.labelMedium?.copyWith(
              color: colors.text,
              fontWeight: FontWeight.w500,
            ),
          ),
        ],
      ),
    );
  }

  StatusColors _getStatusColors(BuildContext context) {
    final scheme = Theme.of(context).colorScheme;

    switch (status) {
      case StatusType.success:
        return StatusColors(
          background: Colors.green.withOpacity(0.1),
          border: Colors.green.withOpacity(0.3),
          indicator: Colors.green,
          text: Colors.green.shade700,
        );
      case StatusType.warning:
        return StatusColors(
          background: Colors.orange.withOpacity(0.1),
          border: Colors.orange.withOpacity(0.3),
          indicator: Colors.orange,
          text: Colors.orange.shade700,
        );
      case StatusType.error:
        return StatusColors(
          background: scheme.errorContainer,
          border: scheme.error.withOpacity(0.3),
          indicator: scheme.error,
          text: scheme.onErrorContainer,
        );
      case StatusType.info:
        return StatusColors(
          background: scheme.primaryContainer,
          border: scheme.primary.withOpacity(0.3),
          indicator: scheme.primary,
          text: scheme.onPrimaryContainer,
        );
    }
  }
}

enum StatusType { success, warning, error, info }

class StatusColors {
  final Color background;
  final Color border;
  final Color indicator;
  final Color text;

  StatusColors({
    required this.background,
    required this.border,
    required this.indicator,
    required this.text,
  });
}

Form Container Patterns

Localized Input Container

class LocalizedInputContainer extends StatelessWidget {
  final String label;
  final String? hint;
  final Widget input;
  final String? errorText;

  const LocalizedInputContainer({
    super.key,
    required this.label,
    this.hint,
    required this.input,
    this.errorText,
  });

  @override
  Widget build(BuildContext context) {
    final hasError = errorText != null;

    return Container(
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: hasError
            ? Theme.of(context).colorScheme.errorContainer.withOpacity(0.3)
            : Theme.of(context).colorScheme.surfaceContainerLowest,
        borderRadius: BorderRadius.circular(12),
        border: Border.all(
          color: hasError
              ? Theme.of(context).colorScheme.error
              : Theme.of(context).colorScheme.outline.withOpacity(0.2),
        ),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            label,
            style: Theme.of(context).textTheme.labelLarge?.copyWith(
              fontWeight: FontWeight.w600,
            ),
          ),
          if (hint != null) ...[
            const SizedBox(height: 4),
            Text(
              hint!,
              style: Theme.of(context).textTheme.bodySmall?.copyWith(
                color: Theme.of(context).colorScheme.outline,
              ),
            ),
          ],
          const SizedBox(height: 12),
          input,
          if (hasError) ...[
            const SizedBox(height: 8),
            Row(
              children: [
                Icon(
                  Icons.error_outline,
                  size: 16,
                  color: Theme.of(context).colorScheme.error,
                ),
                const SizedBox(width: 6),
                Expanded(
                  child: Text(
                    errorText!,
                    style: Theme.of(context).textTheme.bodySmall?.copyWith(
                      color: Theme.of(context).colorScheme.error,
                    ),
                  ),
                ),
              ],
            ),
          ],
        ],
      ),
    );
  }
}

// Usage
class FormContainerExample extends StatelessWidget {
  const FormContainerExample({super.key});

  @override
  Widget build(BuildContext context) {
    final l10n = AppLocalizations.of(context)!;

    return Column(
      children: [
        LocalizedInputContainer(
          label: l10n.emailLabel,
          hint: l10n.emailHint,
          input: const TextField(
            decoration: InputDecoration(
              border: OutlineInputBorder(),
              isDense: true,
            ),
          ),
        ),
        const SizedBox(height: 16),
        LocalizedInputContainer(
          label: l10n.passwordLabel,
          input: const TextField(
            obscureText: true,
            decoration: InputDecoration(
              border: OutlineInputBorder(),
              isDense: true,
            ),
          ),
          errorText: l10n.passwordTooShort,
        ),
      ],
    );
  }
}

Gradient and Complex Decorations

Localized Gradient Container

class LocalizedGradientCard extends StatelessWidget {
  final String title;
  final String subtitle;
  final IconData icon;
  final List<Color> gradientColors;

  const LocalizedGradientCard({
    super.key,
    required this.title,
    required this.subtitle,
    required this.icon,
    required this.gradientColors,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      padding: const EdgeInsets.all(24),
      decoration: BoxDecoration(
        gradient: LinearGradient(
          begin: AlignmentDirectional.topStart,
          end: AlignmentDirectional.bottomEnd,
          colors: gradientColors,
        ),
        borderRadius: BorderRadius.circular(20),
        boxShadow: [
          BoxShadow(
            color: gradientColors.first.withOpacity(0.4),
            blurRadius: 16,
            offset: const Offset(0, 8),
          ),
        ],
      ),
      child: Row(
        children: [
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  title,
                  style: Theme.of(context).textTheme.headlineSmall?.copyWith(
                    color: Colors.white,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                const SizedBox(height: 8),
                Text(
                  subtitle,
                  style: Theme.of(context).textTheme.bodyMedium?.copyWith(
                    color: Colors.white.withOpacity(0.9),
                  ),
                ),
              ],
            ),
          ),
          Container(
            width: 64,
            height: 64,
            decoration: BoxDecoration(
              color: Colors.white.withOpacity(0.2),
              borderRadius: BorderRadius.circular(16),
            ),
            child: Icon(
              icon,
              size: 32,
              color: Colors.white,
            ),
          ),
        ],
      ),
    );
  }
}

Responsive Container Sizing

Adaptive Width Container

class LocalizedResponsiveContainer extends StatelessWidget {
  final Widget child;
  final double maxWidth;
  final EdgeInsetsGeometry padding;

  const LocalizedResponsiveContainer({
    super.key,
    required this.child,
    this.maxWidth = 600,
    this.padding = const EdgeInsets.all(16),
  });

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        constraints: BoxConstraints(maxWidth: maxWidth),
        padding: padding,
        child: child,
      ),
    );
  }
}

// Page layout using responsive container
class LocalizedPageLayout extends StatelessWidget {
  const LocalizedPageLayout({super.key});

  @override
  Widget build(BuildContext context) {
    final l10n = AppLocalizations.of(context)!;

    return Scaffold(
      appBar: AppBar(title: Text(l10n.pageTitle)),
      body: SingleChildScrollView(
        child: LocalizedResponsiveContainer(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                l10n.sectionHeader,
                style: Theme.of(context).textTheme.headlineMedium,
              ),
              const SizedBox(height: 16),
              Text(l10n.sectionContent),
              const SizedBox(height: 24),
              FilledButton(
                onPressed: () {},
                child: Text(l10n.actionButton),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Container Transform Patterns

Directional Transform Container

class DirectionalTransformContainer extends StatelessWidget {
  final Widget child;
  final double rotationAngle;

  const DirectionalTransformContainer({
    super.key,
    required this.child,
    this.rotationAngle = 0,
  });

  @override
  Widget build(BuildContext context) {
    final isRTL = Directionality.of(context) == TextDirection.rtl;

    return Container(
      transform: Matrix4.identity()
        ..rotateZ(isRTL ? -rotationAngle : rotationAngle),
      transformAlignment: Alignment.center,
      child: child,
    );
  }
}

ARB File Structure

English (app_en.arb)

{
  "@@locale": "en",

  "containerContent": "This container demonstrates styling capabilities for multilingual content.",

  "infoMessage": "Here's some helpful information for you.",

  "startAlignedText": "This text is aligned to the start",
  "endAlignedText": "This text is aligned to the end",

  "tipTitle": "Pro Tip",
  "tipDescription": "You can customize this container's appearance using the decoration property.",
  "warningTitle": "Warning",
  "warningDescription": "Please review your changes before saving.",

  "emailLabel": "Email Address",
  "emailHint": "We'll never share your email with anyone else.",
  "passwordLabel": "Password",
  "passwordTooShort": "Password must be at least 8 characters long.",

  "statusActive": "Active",
  "statusPending": "Pending",
  "statusCompleted": "Completed",

  "pageTitle": "Settings",
  "sectionHeader": "Account Settings",
  "sectionContent": "Manage your account preferences and security settings from this page.",
  "actionButton": "Save Changes"
}

German (app_de.arb)

{
  "@@locale": "de",

  "containerContent": "Dieser Container demonstriert Styling-Möglichkeiten für mehrsprachige Inhalte.",

  "infoMessage": "Hier sind einige hilfreiche Informationen für Sie.",

  "startAlignedText": "Dieser Text ist am Anfang ausgerichtet",
  "endAlignedText": "Dieser Text ist am Ende ausgerichtet",

  "tipTitle": "Profi-Tipp",
  "tipDescription": "Sie können das Erscheinungsbild dieses Containers mit der decoration-Eigenschaft anpassen.",
  "warningTitle": "Warnung",
  "warningDescription": "Bitte überprüfen Sie Ihre Änderungen vor dem Speichern.",

  "emailLabel": "E-Mail-Adresse",
  "emailHint": "Wir teilen Ihre E-Mail niemals mit anderen.",
  "passwordLabel": "Passwort",
  "passwordTooShort": "Das Passwort muss mindestens 8 Zeichen lang sein.",

  "statusActive": "Aktiv",
  "statusPending": "Ausstehend",
  "statusCompleted": "Abgeschlossen",

  "pageTitle": "Einstellungen",
  "sectionHeader": "Kontoeinstellungen",
  "sectionContent": "Verwalten Sie Ihre Kontoeinstellungen und Sicherheitsoptionen auf dieser Seite.",
  "actionButton": "Änderungen speichern"
}

Arabic (app_ar.arb)

{
  "@@locale": "ar",

  "containerContent": "يوضح هذا الحاوي إمكانيات التنسيق للمحتوى متعدد اللغات.",

  "infoMessage": "إليك بعض المعلومات المفيدة لك.",

  "startAlignedText": "هذا النص محاذٍ للبداية",
  "endAlignedText": "هذا النص محاذٍ للنهاية",

  "tipTitle": "نصيحة احترافية",
  "tipDescription": "يمكنك تخصيص مظهر هذا الحاوي باستخدام خاصية الزخرفة.",
  "warningTitle": "تحذير",
  "warningDescription": "يرجى مراجعة التغييرات قبل الحفظ.",

  "emailLabel": "عنوان البريد الإلكتروني",
  "emailHint": "لن نشارك بريدك الإلكتروني مع أي شخص آخر.",
  "passwordLabel": "كلمة المرور",
  "passwordTooShort": "يجب أن تتكون كلمة المرور من 8 أحرف على الأقل.",

  "statusActive": "نشط",
  "statusPending": "قيد الانتظار",
  "statusCompleted": "مكتمل",

  "pageTitle": "الإعدادات",
  "sectionHeader": "إعدادات الحساب",
  "sectionContent": "إدارة تفضيلات حسابك وإعدادات الأمان من هذه الصفحة.",
  "actionButton": "حفظ التغييرات"
}

Best Practices Summary

Do's

  1. Use EdgeInsetsDirectional for RTL-aware padding and margins
  2. Use AlignmentDirectional for direction-aware alignment
  3. Combine Container properties to reduce widget nesting
  4. Test decorations with RTL to ensure visual consistency
  5. Use constraints for responsive max-width behavior

Don'ts

  1. Don't nest unnecessary Containers when one will suffice
  2. Don't use EdgeInsets.only when direction matters
  3. Don't forget to test shadows and gradients in RTL
  4. Don't set fixed widths when content length varies significantly

Conclusion

Container is an essential widget for building polished, multilingual Flutter interfaces. Its combination of sizing, padding, decoration, and alignment in one widget simplifies code while providing powerful styling capabilities. Use directional variants for padding and alignment to ensure your containers work seamlessly in both LTR and RTL layouts.

Further Reading