← Back to Blog

Flutter ClipPath Localization: Custom Shape Clipping for Multilingual Apps

flutterclippathclippingcustom-shapeslocalizationrtl

Flutter ClipPath Localization: Custom Shape Clipping for Multilingual Apps

ClipPath clips its child using a custom path, enabling complex shapes like waves, curves, polygons, and custom designs. When combined with localization, ClipPath creates visually stunning UI elements that adapt to different languages and cultural preferences. This guide covers comprehensive strategies for localizing ClipPath widgets in Flutter multilingual applications.

Understanding ClipPath Localization

ClipPath widgets require localization for:

  • Header backgrounds: Wave and curved backgrounds with localized content
  • Profile cards: Custom-shaped profile displays with translated labels
  • Navigation bars: Curved bottom navigation with localized items
  • Decorative elements: Cultural pattern clipping for regional themes
  • Image masks: Custom-shaped image displays with localized overlays
  • Button shapes: Non-rectangular buttons with translated text

Basic ClipPath with Localized Content

Start with a simple custom path clipping example:

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

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

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

    return Scaffold(
      body: Column(
        children: [
          ClipPath(
            clipper: WaveClipper(isRtl: isRtl),
            child: Container(
              height: 250,
              width: double.infinity,
              decoration: BoxDecoration(
                gradient: LinearGradient(
                  begin: isRtl ? Alignment.centerRight : Alignment.centerLeft,
                  end: isRtl ? Alignment.centerLeft : Alignment.centerRight,
                  colors: [
                    Theme.of(context).colorScheme.primary,
                    Theme.of(context).colorScheme.secondary,
                  ],
                ),
              ),
              child: SafeArea(
                child: Padding(
                  padding: const EdgeInsets.all(24),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        l10n.welcomeTitle,
                        style: Theme.of(context).textTheme.headlineMedium?.copyWith(
                          color: Colors.white,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      const SizedBox(height: 8),
                      Text(
                        l10n.welcomeSubtitle,
                        style: Theme.of(context).textTheme.bodyLarge?.copyWith(
                          color: Colors.white.withOpacity(0.9),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ),
          Expanded(
            child: Padding(
              padding: const EdgeInsets.all(16),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    l10n.featuresTitle,
                    style: Theme.of(context).textTheme.titleLarge,
                  ),
                  const SizedBox(height: 16),
                  Expanded(
                    child: ListView(
                      children: [
                        _FeatureItem(
                          icon: Icons.language,
                          title: l10n.featureMultilingual,
                          description: l10n.featureMultilingualDesc,
                        ),
                        _FeatureItem(
                          icon: Icons.design_services,
                          title: l10n.featureCustomDesign,
                          description: l10n.featureCustomDesignDesc,
                        ),
                        _FeatureItem(
                          icon: Icons.accessibility,
                          title: l10n.featureAccessible,
                          description: l10n.featureAccessibleDesc,
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class _FeatureItem extends StatelessWidget {
  final IconData icon;
  final String title;
  final String description;

  const _FeatureItem({
    required this.icon,
    required this.title,
    required this.description,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.only(bottom: 12),
      child: ListTile(
        leading: CircleAvatar(
          backgroundColor: Theme.of(context).colorScheme.primaryContainer,
          child: Icon(icon, color: Theme.of(context).colorScheme.primary),
        ),
        title: Text(title),
        subtitle: Text(description),
      ),
    );
  }
}

class WaveClipper extends CustomClipper<Path> {
  final bool isRtl;

  WaveClipper({required this.isRtl});

  @override
  Path getClip(Size size) {
    final path = Path();
    path.lineTo(0, size.height - 50);

    if (isRtl) {
      // RTL: Wave flows from right to left
      path.quadraticBezierTo(
        size.width * 0.25,
        size.height,
        size.width * 0.5,
        size.height - 30,
      );
      path.quadraticBezierTo(
        size.width * 0.75,
        size.height - 60,
        size.width,
        size.height - 40,
      );
    } else {
      // LTR: Wave flows from left to right
      path.quadraticBezierTo(
        size.width * 0.25,
        size.height - 60,
        size.width * 0.5,
        size.height - 30,
      );
      path.quadraticBezierTo(
        size.width * 0.75,
        size.height,
        size.width,
        size.height - 50,
      );
    }

    path.lineTo(size.width, 0);
    path.close();
    return path;
  }

  @override
  bool shouldReclip(covariant WaveClipper oldClipper) {
    return isRtl != oldClipper.isRtl;
  }
}

ARB File Structure for ClipPath

{
  "welcomeTitle": "Welcome Back",
  "@welcomeTitle": {
    "description": "Welcome title on header"
  },
  "welcomeSubtitle": "Discover what's new today",
  "featuresTitle": "Features",
  "featureMultilingual": "Multilingual Support",
  "featureMultilingualDesc": "Available in over 50 languages",
  "featureCustomDesign": "Custom Design",
  "featureCustomDesignDesc": "Beautiful custom-shaped elements",
  "featureAccessible": "Accessible",
  "featureAccessibleDesc": "Built with accessibility in mind"
}

Curved Profile Card

Create a profile card with custom clipping:

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

class LocalizedProfileCard extends StatelessWidget {
  final String userName;
  final String userRole;
  final String avatarUrl;
  final VoidCallback? onEditProfile;

  const LocalizedProfileCard({
    super.key,
    required this.userName,
    required this.userRole,
    required this.avatarUrl,
    this.onEditProfile,
  });

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

    return Semantics(
      label: l10n.profileCardAccessibility(userName, userRole),
      child: Card(
        elevation: 8,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(20),
        ),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            ClipPath(
              clipper: ProfileHeaderClipper(isRtl: isRtl),
              child: Container(
                height: 150,
                width: double.infinity,
                decoration: BoxDecoration(
                  gradient: LinearGradient(
                    begin: isRtl ? Alignment.topRight : Alignment.topLeft,
                    end: isRtl ? Alignment.bottomLeft : Alignment.bottomRight,
                    colors: [
                      Theme.of(context).colorScheme.primary,
                      Theme.of(context).colorScheme.tertiary,
                    ],
                  ),
                ),
                child: Stack(
                  children: [
                    // Decorative circles
                    Positioned(
                      right: isRtl ? null : -30,
                      left: isRtl ? -30 : null,
                      top: -30,
                      child: Container(
                        width: 100,
                        height: 100,
                        decoration: BoxDecoration(
                          shape: BoxShape.circle,
                          color: Colors.white.withOpacity(0.1),
                        ),
                      ),
                    ),
                    Positioned(
                      left: isRtl ? null : 20,
                      right: isRtl ? 20 : null,
                      bottom: 40,
                      child: Container(
                        width: 60,
                        height: 60,
                        decoration: BoxDecoration(
                          shape: BoxShape.circle,
                          color: Colors.white.withOpacity(0.1),
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
            Transform.translate(
              offset: const Offset(0, -50),
              child: Column(
                children: [
                  Container(
                    decoration: BoxDecoration(
                      shape: BoxShape.circle,
                      border: Border.all(
                        color: Theme.of(context).colorScheme.surface,
                        width: 4,
                      ),
                      boxShadow: [
                        BoxShadow(
                          color: Colors.black.withOpacity(0.2),
                          blurRadius: 10,
                          offset: const Offset(0, 5),
                        ),
                      ],
                    ),
                    child: CircleAvatar(
                      radius: 50,
                      backgroundImage: NetworkImage(avatarUrl),
                    ),
                  ),
                  const SizedBox(height: 12),
                  Text(
                    userName,
                    style: Theme.of(context).textTheme.headlineSmall?.copyWith(
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  const SizedBox(height: 4),
                  Text(
                    userRole,
                    style: Theme.of(context).textTheme.bodyMedium?.copyWith(
                      color: Theme.of(context).colorScheme.onSurfaceVariant,
                    ),
                  ),
                  const SizedBox(height: 16),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      _StatItem(
                        value: '128',
                        label: l10n.profilePosts,
                      ),
                      const SizedBox(width: 32),
                      _StatItem(
                        value: '1.2K',
                        label: l10n.profileFollowers,
                      ),
                      const SizedBox(width: 32),
                      _StatItem(
                        value: '384',
                        label: l10n.profileFollowing,
                      ),
                    ],
                  ),
                  const SizedBox(height: 16),
                  if (onEditProfile != null)
                    Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 24),
                      child: ElevatedButton(
                        onPressed: onEditProfile,
                        style: ElevatedButton.styleFrom(
                          minimumSize: const Size(double.infinity, 48),
                        ),
                        child: Text(l10n.editProfile),
                      ),
                    ),
                  const SizedBox(height: 16),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class _StatItem extends StatelessWidget {
  final String value;
  final String label;

  const _StatItem({required this.value, required this.label});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text(
          value,
          style: Theme.of(context).textTheme.titleLarge?.copyWith(
            fontWeight: FontWeight.bold,
          ),
        ),
        Text(
          label,
          style: Theme.of(context).textTheme.bodySmall?.copyWith(
            color: Theme.of(context).colorScheme.onSurfaceVariant,
          ),
        ),
      ],
    );
  }
}

class ProfileHeaderClipper extends CustomClipper<Path> {
  final bool isRtl;

  ProfileHeaderClipper({required this.isRtl});

  @override
  Path getClip(Size size) {
    final path = Path();
    path.lineTo(0, size.height - 40);

    // Create an asymmetric curve that respects RTL
    if (isRtl) {
      path.cubicTo(
        size.width * 0.2,
        size.height,
        size.width * 0.8,
        size.height - 60,
        size.width,
        size.height - 30,
      );
    } else {
      path.cubicTo(
        size.width * 0.2,
        size.height - 60,
        size.width * 0.8,
        size.height,
        size.width,
        size.height - 30,
      );
    }

    path.lineTo(size.width, 0);
    path.close();
    return path;
  }

  @override
  bool shouldReclip(covariant ProfileHeaderClipper oldClipper) {
    return isRtl != oldClipper.isRtl;
  }
}

Curved Bottom Navigation

Create a bottom navigation bar with custom clipping:

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

class LocalizedCurvedNavigation extends StatefulWidget {
  const LocalizedCurvedNavigation({super.key});

  @override
  State<LocalizedCurvedNavigation> createState() => _LocalizedCurvedNavigationState();
}

class _LocalizedCurvedNavigationState extends State<LocalizedCurvedNavigation> {
  int _selectedIndex = 0;

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

    final items = [
      _NavItem(icon: Icons.home, label: l10n.navHome),
      _NavItem(icon: Icons.search, label: l10n.navSearch),
      _NavItem(icon: Icons.add_circle_outline, label: l10n.navCreate),
      _NavItem(icon: Icons.favorite, label: l10n.navFavorites),
      _NavItem(icon: Icons.person, label: l10n.navProfile),
    ];

    return Scaffold(
      body: IndexedStack(
        index: _selectedIndex,
        children: [
          _PageContent(title: l10n.navHome),
          _PageContent(title: l10n.navSearch),
          _PageContent(title: l10n.navCreate),
          _PageContent(title: l10n.navFavorites),
          _PageContent(title: l10n.navProfile),
        ],
      ),
      bottomNavigationBar: Container(
        height: 80,
        decoration: BoxDecoration(
          boxShadow: [
            BoxShadow(
              color: Colors.black.withOpacity(0.1),
              blurRadius: 20,
              offset: const Offset(0, -5),
            ),
          ],
        ),
        child: ClipPath(
          clipper: CurvedNavClipper(
            selectedIndex: _selectedIndex,
            itemCount: items.length,
            isRtl: isRtl,
          ),
          child: Container(
            color: Theme.of(context).colorScheme.surface,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: List.generate(items.length, (index) {
                final item = items[index];
                final isSelected = index == _selectedIndex;

                return Semantics(
                  label: l10n.navItemAccessibility(item.label, isSelected),
                  selected: isSelected,
                  child: InkWell(
                    onTap: () => setState(() => _selectedIndex = index),
                    child: SizedBox(
                      width: 60,
                      height: 80,
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          AnimatedContainer(
                            duration: const Duration(milliseconds: 200),
                            transform: Matrix4.identity()
                              ..translate(0.0, isSelected ? -10.0 : 0.0),
                            child: Container(
                              padding: const EdgeInsets.all(12),
                              decoration: isSelected
                                  ? BoxDecoration(
                                      color: Theme.of(context).colorScheme.primary,
                                      shape: BoxShape.circle,
                                      boxShadow: [
                                        BoxShadow(
                                          color: Theme.of(context)
                                              .colorScheme
                                              .primary
                                              .withOpacity(0.4),
                                          blurRadius: 10,
                                          offset: const Offset(0, 5),
                                        ),
                                      ],
                                    )
                                  : null,
                              child: Icon(
                                item.icon,
                                color: isSelected
                                    ? Colors.white
                                    : Theme.of(context).colorScheme.onSurfaceVariant,
                              ),
                            ),
                          ),
                          if (!isSelected) ...[
                            const SizedBox(height: 4),
                            Text(
                              item.label,
                              style: Theme.of(context).textTheme.labelSmall?.copyWith(
                                color: Theme.of(context).colorScheme.onSurfaceVariant,
                              ),
                              maxLines: 1,
                              overflow: TextOverflow.ellipsis,
                            ),
                          ],
                        ],
                      ),
                    ),
                  ),
                );
              }),
            ),
          ),
        ),
      ),
    );
  }
}

class _NavItem {
  final IconData icon;
  final String label;

  _NavItem({required this.icon, required this.label});
}

class _PageContent extends StatelessWidget {
  final String title;

  const _PageContent({required this.title});

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(
        title,
        style: Theme.of(context).textTheme.headlineMedium,
      ),
    );
  }
}

class CurvedNavClipper extends CustomClipper<Path> {
  final int selectedIndex;
  final int itemCount;
  final bool isRtl;

  CurvedNavClipper({
    required this.selectedIndex,
    required this.itemCount,
    required this.isRtl,
  });

  @override
  Path getClip(Size size) {
    final path = Path();
    final itemWidth = size.width / itemCount;

    // Adjust index for RTL
    final adjustedIndex = isRtl ? (itemCount - 1 - selectedIndex) : selectedIndex;
    final centerX = itemWidth * adjustedIndex + itemWidth / 2;

    path.lineTo(0, 20);

    // Left side of curve
    if (centerX > itemWidth) {
      path.lineTo(centerX - itemWidth * 0.8, 20);
    }

    // Create the notch curve
    path.quadraticBezierTo(
      centerX - itemWidth * 0.5,
      20,
      centerX - itemWidth * 0.3,
      0,
    );
    path.quadraticBezierTo(
      centerX,
      -25,
      centerX + itemWidth * 0.3,
      0,
    );
    path.quadraticBezierTo(
      centerX + itemWidth * 0.5,
      20,
      centerX + itemWidth * 0.8,
      20,
    );

    // Right side
    path.lineTo(size.width, 20);
    path.lineTo(size.width, size.height);
    path.lineTo(0, size.height);
    path.close();

    return path;
  }

  @override
  bool shouldReclip(covariant CurvedNavClipper oldClipper) {
    return selectedIndex != oldClipper.selectedIndex ||
        itemCount != oldClipper.itemCount ||
        isRtl != oldClipper.isRtl;
  }
}

Cultural Pattern Clipping

Create region-specific decorative patterns:

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

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

  @override
  Widget build(BuildContext context) {
    final l10n = AppLocalizations.of(context)!;
    final locale = Localizations.localeOf(context);
    final isRtl = Directionality.of(context) == TextDirection.rtl;

    return Scaffold(
      appBar: AppBar(title: Text(l10n.culturalPatternsTitle)),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          Text(
            l10n.culturalPatternsDescription,
            style: Theme.of(context).textTheme.bodyLarge,
          ),
          const SizedBox(height: 24),
          _PatternCard(
            patternType: _getPatternForLocale(locale),
            title: l10n.regionalPatternTitle,
            description: l10n.regionalPatternDescription,
            isRtl: isRtl,
          ),
          const SizedBox(height: 16),
          _PatternCard(
            patternType: PatternType.geometric,
            title: l10n.geometricPatternTitle,
            description: l10n.geometricPatternDescription,
            isRtl: isRtl,
          ),
          const SizedBox(height: 16),
          _PatternCard(
            patternType: PatternType.organic,
            title: l10n.organicPatternTitle,
            description: l10n.organicPatternDescription,
            isRtl: isRtl,
          ),
        ],
      ),
    );
  }

  PatternType _getPatternForLocale(Locale locale) {
    switch (locale.languageCode) {
      case 'ar':
      case 'fa':
      case 'ur':
        return PatternType.arabesque;
      case 'ja':
      case 'zh':
      case 'ko':
        return PatternType.eastAsian;
      case 'hi':
      case 'bn':
      case 'ta':
        return PatternType.mandala;
      default:
        return PatternType.modern;
    }
  }
}

enum PatternType { arabesque, eastAsian, mandala, modern, geometric, organic }

class _PatternCard extends StatelessWidget {
  final PatternType patternType;
  final String title;
  final String description;
  final bool isRtl;

  const _PatternCard({
    required this.patternType,
    required this.title,
    required this.description,
    required this.isRtl,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      clipBehavior: Clip.antiAlias,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          ClipPath(
            clipper: _PatternClipper(
              patternType: patternType,
              isRtl: isRtl,
            ),
            child: Container(
              height: 120,
              decoration: BoxDecoration(
                gradient: LinearGradient(
                  begin: isRtl ? Alignment.centerRight : Alignment.centerLeft,
                  end: isRtl ? Alignment.centerLeft : Alignment.centerRight,
                  colors: _getPatternColors(context, patternType),
                ),
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(16),
            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,
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  List<Color> _getPatternColors(BuildContext context, PatternType type) {
    final scheme = Theme.of(context).colorScheme;
    switch (type) {
      case PatternType.arabesque:
        return [const Color(0xFF1B5E20), const Color(0xFF4CAF50)];
      case PatternType.eastAsian:
        return [const Color(0xFFC62828), const Color(0xFFEF5350)];
      case PatternType.mandala:
        return [const Color(0xFFE65100), const Color(0xFFFF9800)];
      case PatternType.modern:
        return [scheme.primary, scheme.tertiary];
      case PatternType.geometric:
        return [const Color(0xFF1565C0), const Color(0xFF42A5F5)];
      case PatternType.organic:
        return [const Color(0xFF6A1B9A), const Color(0xFFAB47BC)];
    }
  }
}

class _PatternClipper extends CustomClipper<Path> {
  final PatternType patternType;
  final bool isRtl;

  _PatternClipper({required this.patternType, required this.isRtl});

  @override
  Path getClip(Size size) {
    switch (patternType) {
      case PatternType.arabesque:
        return _createArabesquePath(size);
      case PatternType.eastAsian:
        return _createEastAsianPath(size);
      case PatternType.mandala:
        return _createMandalaPath(size);
      case PatternType.modern:
        return _createModernPath(size);
      case PatternType.geometric:
        return _createGeometricPath(size);
      case PatternType.organic:
        return _createOrganicPath(size);
    }
  }

  Path _createArabesquePath(Size size) {
    final path = Path();
    path.lineTo(0, size.height - 30);

    // Arabesque-inspired scalloped edge
    final scallops = 8;
    final scallopsWidth = size.width / scallops;

    for (int i = 0; i < scallops; i++) {
      final startX = i * scallopsWidth;
      final endX = (i + 1) * scallopsWidth;
      final midX = startX + scallopsWidth / 2;

      path.quadraticBezierTo(
        midX,
        size.height,
        endX,
        size.height - 30,
      );
    }

    path.lineTo(size.width, 0);
    path.close();
    return path;
  }

  Path _createEastAsianPath(Size size) {
    final path = Path();
    path.lineTo(0, size.height - 20);

    // Cloud-inspired stepped pattern
    final steps = 6;
    final stepWidth = size.width / steps;

    for (int i = 0; i < steps; i++) {
      final startX = i * stepWidth;
      final midX = startX + stepWidth / 2;
      final endX = (i + 1) * stepWidth;
      final y = size.height - 20 - (i % 2 == 0 ? 0 : 15);

      path.lineTo(midX, y);
      path.lineTo(endX, size.height - 20);
    }

    path.lineTo(size.width, 0);
    path.close();
    return path;
  }

  Path _createMandalaPath(Size size) {
    final path = Path();
    final center = Offset(size.width / 2, size.height);
    final radius = size.width / 2;

    path.lineTo(0, size.height);

    // Create petal-like pattern at the bottom
    final petals = 12;
    for (int i = 0; i <= petals; i++) {
      final angle = math.pi * i / petals;
      final petalRadius = radius - (i % 2 == 0 ? 20 : 40);
      final x = center.dx + petalRadius * math.cos(angle);
      final y = size.height - petalRadius * math.sin(angle).abs() * 0.5;

      if (i == 0) {
        path.lineTo(x, y);
      } else {
        path.lineTo(x, y);
      }
    }

    path.lineTo(size.width, size.height);
    path.lineTo(size.width, 0);
    path.lineTo(0, 0);
    path.close();
    return path;
  }

  Path _createModernPath(Size size) {
    final path = Path();
    path.lineTo(0, size.height - 40);

    if (isRtl) {
      path.cubicTo(
        size.width * 0.3,
        size.height - 60,
        size.width * 0.7,
        size.height,
        size.width,
        size.height - 20,
      );
    } else {
      path.cubicTo(
        size.width * 0.3,
        size.height,
        size.width * 0.7,
        size.height - 60,
        size.width,
        size.height - 20,
      );
    }

    path.lineTo(size.width, 0);
    path.close();
    return path;
  }

  Path _createGeometricPath(Size size) {
    final path = Path();
    path.lineTo(0, size.height - 30);

    // Zigzag pattern
    final segments = 10;
    final segmentWidth = size.width / segments;

    for (int i = 0; i < segments; i++) {
      final x = (i + 1) * segmentWidth;
      final y = size.height - (i % 2 == 0 ? 30 : 50);
      path.lineTo(x, y);
    }

    path.lineTo(size.width, 0);
    path.close();
    return path;
  }

  Path _createOrganicPath(Size size) {
    final path = Path();
    path.lineTo(0, size.height - 25);

    // Smooth organic wave
    path.cubicTo(
      size.width * 0.2,
      size.height - 50,
      size.width * 0.35,
      size.height,
      size.width * 0.5,
      size.height - 30,
    );
    path.cubicTo(
      size.width * 0.65,
      size.height - 60,
      size.width * 0.8,
      size.height - 10,
      size.width,
      size.height - 35,
    );

    path.lineTo(size.width, 0);
    path.close();
    return path;
  }

  @override
  bool shouldReclip(covariant _PatternClipper oldClipper) {
    return patternType != oldClipper.patternType || isRtl != oldClipper.isRtl;
  }
}

Diagonal Section Divider

Create a diagonal divider between content sections:

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

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

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

    return Scaffold(
      body: SingleChildScrollView(
        child: Column(
          children: [
            // Hero Section
            Container(
              height: 300,
              width: double.infinity,
              color: Theme.of(context).colorScheme.primary,
              child: SafeArea(
                child: Padding(
                  padding: const EdgeInsets.all(24),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Text(
                        l10n.heroTitle,
                        style: Theme.of(context).textTheme.headlineLarge?.copyWith(
                          color: Colors.white,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      const SizedBox(height: 12),
                      Text(
                        l10n.heroSubtitle,
                        style: Theme.of(context).textTheme.bodyLarge?.copyWith(
                          color: Colors.white.withOpacity(0.9),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),

            // Diagonal Transition
            ClipPath(
              clipper: DiagonalClipper(
                direction: isRtl ? DiagonalDirection.rightToLeft : DiagonalDirection.leftToRight,
              ),
              child: Container(
                height: 80,
                color: Theme.of(context).colorScheme.primary,
              ),
            ),

            // Features Section
            Transform.translate(
              offset: const Offset(0, -40),
              child: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 16),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      l10n.aboutSectionTitle,
                      style: Theme.of(context).textTheme.headlineSmall?.copyWith(
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    const SizedBox(height: 16),
                    Text(
                      l10n.aboutSectionContent,
                      style: Theme.of(context).textTheme.bodyLarge,
                    ),
                  ],
                ),
              ),
            ),

            const SizedBox(height: 40),

            // Second Section with Reversed Diagonal
            Container(
              color: Theme.of(context).colorScheme.secondaryContainer,
              child: Column(
                children: [
                  ClipPath(
                    clipper: DiagonalClipper(
                      direction: isRtl ? DiagonalDirection.leftToRight : DiagonalDirection.rightToLeft,
                      position: DiagonalPosition.top,
                    ),
                    child: Container(
                      height: 60,
                      color: Theme.of(context).colorScheme.secondaryContainer,
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.all(24),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          l10n.featuresSectionTitle,
                          style: Theme.of(context).textTheme.headlineSmall?.copyWith(
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                        const SizedBox(height: 16),
                        ...List.generate(3, (index) => Padding(
                          padding: const EdgeInsets.only(bottom: 12),
                          child: Row(
                            children: [
                              Icon(
                                Icons.check_circle,
                                color: Theme.of(context).colorScheme.primary,
                              ),
                              const SizedBox(width: 12),
                              Expanded(
                                child: Text(
                                  l10n.featureItem(index + 1),
                                  style: Theme.of(context).textTheme.bodyLarge,
                                ),
                              ),
                            ],
                          ),
                        )),
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

enum DiagonalDirection { leftToRight, rightToLeft }
enum DiagonalPosition { top, bottom }

class DiagonalClipper extends CustomClipper<Path> {
  final DiagonalDirection direction;
  final DiagonalPosition position;

  DiagonalClipper({
    required this.direction,
    this.position = DiagonalPosition.bottom,
  });

  @override
  Path getClip(Size size) {
    final path = Path();

    if (position == DiagonalPosition.bottom) {
      if (direction == DiagonalDirection.leftToRight) {
        path.lineTo(0, 0);
        path.lineTo(size.width, size.height);
        path.lineTo(0, size.height);
      } else {
        path.lineTo(size.width, 0);
        path.lineTo(size.width, size.height);
        path.lineTo(0, size.height);
      }
    } else {
      if (direction == DiagonalDirection.leftToRight) {
        path.lineTo(0, size.height);
        path.lineTo(size.width, 0);
        path.lineTo(size.width, size.height);
      } else {
        path.moveTo(size.width, size.height);
        path.lineTo(0, 0);
        path.lineTo(0, size.height);
      }
    }

    path.close();
    return path;
  }

  @override
  bool shouldReclip(covariant DiagonalClipper oldClipper) {
    return direction != oldClipper.direction || position != oldClipper.position;
  }
}

Complete ARB File for ClipPath

{
  "@@locale": "en",

  "welcomeTitle": "Welcome Back",
  "welcomeSubtitle": "Discover what's new today",
  "featuresTitle": "Features",
  "featureMultilingual": "Multilingual Support",
  "featureMultilingualDesc": "Available in over 50 languages",
  "featureCustomDesign": "Custom Design",
  "featureCustomDesignDesc": "Beautiful custom-shaped elements",
  "featureAccessible": "Accessible",
  "featureAccessibleDesc": "Built with accessibility in mind",

  "profileCardAccessibility": "Profile card for {name}, {role}",
  "@profileCardAccessibility": {
    "placeholders": {
      "name": {"type": "String"},
      "role": {"type": "String"}
    }
  },
  "profilePosts": "Posts",
  "profileFollowers": "Followers",
  "profileFollowing": "Following",
  "editProfile": "Edit Profile",

  "navHome": "Home",
  "navSearch": "Search",
  "navCreate": "Create",
  "navFavorites": "Favorites",
  "navProfile": "Profile",
  "navItemAccessibility": "{label}, {selected, select, true{selected} other{not selected}}",
  "@navItemAccessibility": {
    "placeholders": {
      "label": {"type": "String"},
      "selected": {"type": "String"}
    }
  },

  "culturalPatternsTitle": "Cultural Patterns",
  "culturalPatternsDescription": "Explore decorative patterns inspired by different cultures",
  "regionalPatternTitle": "Regional Pattern",
  "regionalPatternDescription": "Pattern inspired by your region's artistic traditions",
  "geometricPatternTitle": "Geometric Pattern",
  "geometricPatternDescription": "Clean lines and mathematical precision",
  "organicPatternTitle": "Organic Pattern",
  "organicPatternDescription": "Flowing curves inspired by nature",

  "heroTitle": "Build Beautiful Apps",
  "heroSubtitle": "Create stunning user interfaces with custom clipping",
  "aboutSectionTitle": "About Our Platform",
  "aboutSectionContent": "We provide the tools you need to create world-class applications with beautiful custom designs that work across all languages and cultures.",
  "featuresSectionTitle": "Key Features",
  "featureItem": "Feature number {number} with full localization support",
  "@featureItem": {
    "placeholders": {
      "number": {"type": "int"}
    }
  }
}

Best Practices Summary

  1. Use RTL-aware paths: Create custom clippers that respect text direction
  2. Test all locales: Verify clipping looks correct in different languages
  3. Provide semantic labels: Describe clipped regions for accessibility
  4. Consider cultural context: Use region-appropriate decorative patterns
  5. Animate thoughtfully: Smooth transitions when paths change
  6. Handle edge cases: Ensure paths work at all container sizes
  7. Use shouldReclip correctly: Only reclip when necessary for performance
  8. Combine with gradients: Direction-aware gradients complement clipping
  9. Layer appropriately: Use Stack for complex clipped compositions
  10. Test on devices: Clipping can look different across screen sizes

Conclusion

ClipPath provides unlimited creative possibilities for custom-shaped UI elements that adapt to different languages and cultural contexts. By creating RTL-aware custom clippers and considering regional design preferences, you can build visually stunning applications that feel native to users worldwide. The key is using CustomClipper with direction awareness and testing thoroughly across all supported locales to ensure your custom shapes enhance rather than hinder the user experience.

Remember to balance creative expression with usability, ensuring that clipped elements remain accessible and functional in all languages your application supports.