Skip to main content

dynamic_app_translator 1.0.6 copy "dynamic_app_translator: ^1.0.6" to clipboard
dynamic_app_translator: ^1.0.6 copied to clipboard

Real-time dynamic translation package for Flutter applications using TranslatX API with offline disk caching and instant language switcher.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:dynamic_app_translator/dynamic_app_translator.dart';
import 'dart:ui';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await DynamicTranslatorController.instance.init(
    defaultLanguage: 'en',
    backendUrl: 'https://translater-free-api.onrender.com/api/v1/translate',
  );
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: DynamicTranslatorController.instance,
      builder: (context, _) {
        return MaterialApp(
          title: 'Transflow',
          debugShowCheckedModeBanner: false,
          theme: ThemeData(
            useMaterial3: true,
            scaffoldBackgroundColor: const Color(0xFFFAF8FF),
            colorScheme: ColorScheme.fromSeed(
              seedColor: const Color(0xFF2A14B4),
              primary: const Color(0xFF2A14B4),
              secondary: const Color(0xFF712AE2),
              surface: const Color(0xFFFAF8FF),
              onSurface: const Color(0xFF131B2E),
            ),
            fontFamily: 'Inter',
          ),
          home: TransflowHomeScreen(),
        );
      },
    );
  }
}

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

  @override
  State<TransflowHomeScreen> createState() => _TransflowHomeScreenState();
}

class _TransflowHomeScreenState extends State<TransflowHomeScreen> {
  final TextEditingController _sourceController = TextEditingController();
  int _charCount = 0;
  bool _isTranslating = false;
  String _submittedText = "";
  
  final List<Map<String, String>> _languages = [
    {'code': 'hi', 'name': 'Hindi'},
    {'code': 'es', 'name': 'Spanish'},
    {'code': 'ja', 'name': 'Japanese'},
    {'code': 'de', 'name': 'German'},
    {'code': 'fr', 'name': 'French'},
    {'code': 'ar', 'name': 'Arabic'},
  ];

  @override
  void initState() {
    super.initState();
    _sourceController.text = "";
    _charCount = 0;
    
    // Listen for translation completion to hide spinner smoothly
    DynamicTranslatorController.instance.addListener(() {
      if (mounted && _isTranslating) {
        // As soon as the controller finishes fetching and notifies, stop the spinner.
        setState(() {
          _isTranslating = false;
        });
      }
    });
  }

  void _translate() {
    if (_isTranslating || _sourceController.text.trim().isEmpty) return;
    
    setState(() {
      _isTranslating = true;
      _submittedText = _sourceController.text;
    });
    
    final translated = DynamicTranslatorController.instance.translate(_submittedText);
    
    // If it's already cached or English, stop loading immediately
    if (translated != _submittedText || DynamicTranslatorController.instance.currentLanguage == 'en') {
      setState(() {
        _isTranslating = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      extendBodyBehindAppBar: true,
      appBar: PreferredSize(
        preferredSize: const Size.fromHeight(64),
        child: ClipRRect(
          child: BackdropFilter(
            filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
            child: AppBar(
              backgroundColor: const Color(0xFFFAF8FF).withOpacity(0.8),
              elevation: 0,
              scrolledUnderElevation: 1,
              shadowColor: Colors.black.withOpacity(0.1),
              title: Row(
                children: [
                  const Icon(Icons.translate, color: Color(0xFF2A14B4), size: 28),
                  const SizedBox(width: 8),
                  Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Row(
                        children: [
                          const Text(
                            "Transflow",
                            style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Color(0xFF131B2E)),
                          ),
                          const SizedBox(width: 4),
                          Text(
                            "/ Translate",
                            style: TextStyle(fontSize: 13, color: const Color(0xFF464554).withOpacity(0.7)),
                          ),
                        ],
                      ),
                      Container(
                        margin: const EdgeInsets.only(top: 2),
                        padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
                        decoration: BoxDecoration(
                          color: const Color(0xFF005A6A).withOpacity(0.15),
                          borderRadius: BorderRadius.circular(12),
                        ),
                        child: Row(
                          children: [
                            Container(
                              width: 6, height: 6,
                              decoration: const BoxDecoration(color: Color(0xFF4CD7F6), shape: BoxShape.circle),
                            ),
                            const SizedBox(width: 4),
                            const Text(
                              "v2.4.0 • SDK Ready",
                              style: TextStyle(fontSize: 9, color: Color(0xFF00414D), fontWeight: FontWeight.bold),
                            ),
                          ],
                        ),
                      ),
                    ],
                  ),
                ],
              ),
              actions: [
                IconButton(
                  icon: const Icon(Icons.tune, color: Color(0xFF464554)),
                  onPressed: () {},
                ),
                Padding(
                  padding: const EdgeInsets.only(right: 16.0),
                  child: Container(
                    decoration: BoxDecoration(
                      shape: BoxShape.circle,
                      border: Border.all(color: const Color(0xFF2A14B4).withOpacity(0.1), width: 2),
                    ),
                    child: const CircleAvatar(
                      radius: 16,
                      backgroundColor: Color(0xFFEADDFF),
                      child: Icon(Icons.person, size: 20, color: Color(0xFF2A14B4)),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
      body: SafeArea(
        child: SingleChildScrollView(
          padding: const EdgeInsets.fromLTRB(16, 16, 16, 100),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              // Engine Status
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Row(
                    children: [
                      Container(
                        padding: const EdgeInsets.all(4),
                        decoration: BoxDecoration(
                          color: const Color(0xFF2A14B4).withOpacity(0.1),
                          shape: BoxShape.circle,
                        ),
                        child: const Icon(Icons.psychology, size: 15, color: Color(0xFF2A14B4)),
                      ),
                      const SizedBox(width: 6),
                      const Text(
                        "UNIVERSAL LANGUAGE ENGINE",
                        style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold, color: Color(0xFF464554)),
                      ),
                    ],
                  ),
                  Container(
                    padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
                    decoration: BoxDecoration(
                      color: const Color(0xFFEAEDFF),
                      borderRadius: BorderRadius.circular(12),
                    ),
                    child: Row(
                      children: [
                        Container(
                          width: 6, height: 6,
                          decoration: const BoxDecoration(color: Color(0xFF2A14B4), shape: BoxShape.circle),
                        ),
                        const SizedBox(width: 4),
                        const Text(
                          "Neural v4.2 Local",
                          style: TextStyle(fontSize: 10, color: Color(0xFF2A14B4), fontWeight: FontWeight.w600),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 16),

              // Language Switcher Card
              Container(
                padding: const EdgeInsets.all(8),
                decoration: BoxDecoration(
                  color: Colors.white,
                  borderRadius: BorderRadius.circular(12),
                  boxShadow: [
                    BoxShadow(
                      color: Colors.black.withOpacity(0.03),
                      blurRadius: 4,
                      offset: const Offset(0, 2),
                    ),
                  ],
                ),
                child: Row(
                  children: [
                    Expanded(
                      child: Container(
                        padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
                        decoration: BoxDecoration(
                          color: const Color(0xFFF2F3FF),
                          borderRadius: BorderRadius.circular(8),
                        ),
                        child: const Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text("FROM", style: TextStyle(fontSize: 10, color: Color(0xFF777586), fontWeight: FontWeight.bold)),
                            Text("Auto-Detect (English)", style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold, color: Color(0xFF131B2E))),
                          ],
                        ),
                      ),
                    ),
                    const Padding(
                      padding: EdgeInsets.symmetric(horizontal: 8.0),
                      child: Icon(Icons.swap_horiz, color: Color(0xFF2A14B4)),
                    ),
                    Expanded(
                      child: Container(
                        padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
                        decoration: BoxDecoration(
                          color: const Color(0xFFE3DFFF).withOpacity(0.5),
                          borderRadius: BorderRadius.circular(8),
                        ),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            const Text("TO", style: TextStyle(fontSize: 10, color: Color(0xFF2A14B4), fontWeight: FontWeight.bold)),
                            Text(
                              DynamicTranslatorController.instance.currentLanguage.toUpperCase(),
                              style: const TextStyle(fontSize: 15, fontWeight: FontWeight.bold, color: Color(0xFF2A14B4)),
                            ),
                          ],
                        ),
                      ),
                    ),
                  ],
                ),
              ),
              const SizedBox(height: 16),

              // Language Chips
              SizedBox(
                height: 36,
                child: ListView.builder(
                  scrollDirection: Axis.horizontal,
                  itemCount: _languages.length,
                  itemBuilder: (context, index) {
                    final lang = _languages[index];
                    final isActive = DynamicTranslatorController.instance.currentLanguage == lang['code'];
                    return Padding(
                      padding: const EdgeInsets.only(right: 8.0),
                      child: InkWell(
                        onTap: () {
                          DynamicTranslatorController.instance.changeLanguage(lang['code']!);
                        },
                        borderRadius: BorderRadius.circular(20),
                        child: Container(
                          padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                          decoration: BoxDecoration(
                            color: isActive ? const Color(0xFF2A14B4) : Colors.white,
                            borderRadius: BorderRadius.circular(20),
                            boxShadow: [
                              if (!isActive) BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 2),
                            ],
                          ),
                          child: Row(
                            children: [
                              if (isActive) const Icon(Icons.check, size: 14, color: Colors.white),
                              if (isActive) const SizedBox(width: 4),
                              Text(
                                lang['name']!,
                                style: TextStyle(
                                  fontSize: 13,
                                  fontWeight: isActive ? FontWeight.bold : FontWeight.w500,
                                  color: isActive ? Colors.white : const Color(0xFF464554),
                                ),
                              ),
                            ],
                          ),
                        ),
                      ),
                    );
                  },
                ),
              ),
              const SizedBox(height: 16),

              // Source Input Box
              Container(
                height: 170,
                padding: const EdgeInsets.all(16),
                decoration: BoxDecoration(
                  color: Colors.white,
                  borderRadius: BorderRadius.circular(16),
                  boxShadow: [
                    BoxShadow(color: Colors.black.withOpacity(0.04), blurRadius: 8),
                  ],
                ),
                child: Column(
                  children: [
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        const Text("SOURCE TEXT", style: TextStyle(fontSize: 10, fontWeight: FontWeight.bold, color: Color(0xFF777586))),
                        Row(
                          children: [
                            InkWell(
                              onTap: () {
                                setState(() {
                                  _sourceController.clear();
                                  _charCount = 0;
                                });
                              },
                              child: const Text("Clear", style: TextStyle(fontSize: 12, color: Color(0xFF464554))),
                            ),
                          ],
                        ),
                      ],
                    ),
                    Expanded(
                      child: TextField(
                        controller: _sourceController,
                        maxLines: null,
                        style: const TextStyle(fontSize: 18, color: Color(0xFF131B2E)),
                        decoration: const InputDecoration(
                          border: InputBorder.none,
                          hintText: "Type or paste text to translate...",
                        ),
                        onChanged: (val) {
                          setState(() {
                            _charCount = val.length;
                          });
                        },
                      ),
                    ),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Row(
                          children: [
                            Container(
                              padding: const EdgeInsets.all(6),
                              decoration: const BoxDecoration(color: Color(0xFFF2F3FF), shape: BoxShape.circle),
                              child: const Icon(Icons.mic, size: 20, color: Color(0xFF2A14B4)),
                            ),
                            const SizedBox(width: 8),
                            Container(
                              padding: const EdgeInsets.all(6),
                              decoration: const BoxDecoration(color: Color(0xFFF2F3FF), shape: BoxShape.circle),
                              child: const Icon(Icons.volume_up, size: 20, color: Color(0xFF777586)),
                            ),
                          ],
                        ),
                        Text(
                          "$_charCount / 5,000",
                          style: const TextStyle(fontSize: 12, color: Color(0xFF777586)),
                        ),
                      ],
                    ),
                  ],
                ),
              ),
              const SizedBox(height: 16),

              // Translate Button
              InkWell(
                onTap: _translate,
                borderRadius: BorderRadius.circular(12),
                child: Container(
                  height: 52,
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(12),
                    gradient: const LinearGradient(
                      colors: [Color(0xFF2A14B4), Color(0xFF4338CA), Color(0xFF712AE2)],
                    ),
                    boxShadow: [
                      BoxShadow(color: const Color(0xFF2A14B4).withOpacity(0.3), blurRadius: 10, offset: const Offset(0, 4)),
                    ],
                  ),
                  child: Center(
                    child: _isTranslating 
                        ? const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(color: Colors.white, strokeWidth: 2))
                        : const Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: [
                              Icon(Icons.auto_awesome, color: Colors.white, size: 20),
                              SizedBox(width: 8),
                              Text(
                                "Instant Translate",
                                style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.white),
                              ),
                            ],
                          ),
                  ),
                ),
              ),
              const SizedBox(height: 8),

              // Telemetry bar
              Container(
                padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
                decoration: BoxDecoration(
                  color: const Color(0xFFF2F3FF),
                  borderRadius: BorderRadius.circular(8),
                ),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Row(
                      children: [
                        const Icon(Icons.bolt, size: 16, color: Color(0xFF005A6A)),
                        const SizedBox(width: 4),
                        Text("14ms latency", style: TextStyle(fontSize: 11, fontWeight: FontWeight.bold, color: const Color(0xFF131B2E).withOpacity(0.8))),
                      ],
                    ),
                    const Row(
                      children: [
                        Text("Cache hit • ", style: TextStyle(fontSize: 11, color: Color(0xFF464554))),
                        Text("99.8% confidence", style: TextStyle(fontSize: 11, fontWeight: FontWeight.bold, color: Color(0xFF2A14B4))),
                      ],
                    ),
                  ],
                ),
              ),
              const SizedBox(height: 16),

              // Output Box
              Container(
                height: 190,
                padding: const EdgeInsets.all(16),
                decoration: BoxDecoration(
                  color: const Color(0xFFEAEDFF),
                  borderRadius: BorderRadius.circular(16),
                ),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Row(
                          children: [
                            Text(
                              "${DynamicTranslatorController.instance.currentLanguage.toUpperCase()} OUTPUT", 
                              style: const TextStyle(fontSize: 10, fontWeight: FontWeight.bold, color: Color(0xFF2A14B4))
                            ),
                            const SizedBox(width: 8),
                            Container(
                              padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
                              decoration: BoxDecoration(
                                color: const Color(0xFFE2E7FF),
                                borderRadius: BorderRadius.circular(4),
                              ),
                              child: const Text("Natural Fast-Inference", style: TextStyle(fontSize: 10, color: Color(0xFF2A14B4))),
                            ),
                          ],
                        ),
                        const Icon(Icons.star_border, color: Color(0xFF777586), size: 20),
                      ],
                    ),
                    const SizedBox(height: 12),
                    Expanded(
                      child: AnimatedBuilder(
                        animation: DynamicTranslatorController.instance,
                        builder: (context, _) {
                          return Text(
                            _submittedText.isNotEmpty ? _submittedText.tr() : "Translation will appear here...",
                            style: TextStyle(
                              fontSize: 20, 
                              fontWeight: FontWeight.w500, 
                              color: _submittedText.isNotEmpty ? const Color(0xFF131B2E) : const Color(0xFF777586).withOpacity(0.5)
                            ),
                          );
                        }
                      ),
                    ),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Row(
                          children: [
                            Container(
                              padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
                              decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(20)),
                              child: const Row(
                                children: [
                                  Icon(Icons.volume_up, size: 16, color: Color(0xFF2A14B4)),
                                  SizedBox(width: 4),
                                  Text("Listen", style: TextStyle(fontSize: 12, color: Color(0xFF2A14B4), fontWeight: FontWeight.bold)),
                                ],
                              ),
                            ),
                            const SizedBox(width: 8),
                            Container(
                              padding: const EdgeInsets.all(6),
                              decoration: const BoxDecoration(color: Colors.white, shape: BoxShape.circle),
                              child: const Icon(Icons.share, size: 16, color: Color(0xFF777586)),
                            ),
                          ],
                        ),
                        Container(
                          padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
                          decoration: BoxDecoration(color: const Color(0xFF4338CA), borderRadius: BorderRadius.circular(20)),
                          child: const Row(
                            children: [
                              Icon(Icons.copy, size: 16, color: Colors.white),
                              SizedBox(width: 4),
                              Text("Copy", style: TextStyle(fontSize: 12, color: Colors.white, fontWeight: FontWeight.bold)),
                            ],
                          ),
                        ),
                      ],
                    ),
                  ],
                ),
              ),
              const SizedBox(height: 12),
              
              const Center(
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Icon(Icons.verified, size: 14, color: Color(0xFF00414D)),
                    SizedBox(width: 4),
                    Text(
                      "Powered by Transflow Core Engine • Offline Mode Supported",
                      style: TextStyle(fontSize: 10, color: Color(0xFF777586)),
                    ),
                  ],
                ),
              )
            ],
          ),
        ),
      ),
      bottomNavigationBar: Container(
        height: 64,
        decoration: BoxDecoration(
          color: const Color(0xFFFAF8FF).withOpacity(0.9),
          boxShadow: [
            BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, -2)),
          ],
        ),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: [
            _buildNavItem(Icons.translate, "Translate", true),
            _buildNavItem(Icons.terminal, "Playground", false),
            _buildNavItem(Icons.history, "History", false),
            _buildNavItem(Icons.tune, "Models", false),
          ],
        ),
      ),
    );
  }

  Widget _buildNavItem(IconData icon, String label, bool isActive) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Container(
          padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
          decoration: BoxDecoration(
            color: isActive ? const Color(0xFF4338CA).withOpacity(0.1) : Colors.transparent,
            borderRadius: BorderRadius.circular(16),
          ),
          child: Icon(icon, color: isActive ? const Color(0xFF2A14B4) : const Color(0xFF777586), size: 24),
        ),
        const SizedBox(height: 4),
        Text(
          label,
          style: TextStyle(
            fontSize: 10,
            fontWeight: isActive ? FontWeight.bold : FontWeight.w500,
            color: isActive ? const Color(0xFF2A14B4) : const Color(0xFF777586),
          ),
        ),
      ],
    );
  }
}
1
likes
160
points
644
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Real-time dynamic translation package for Flutter applications using TranslatX API with offline disk caching and instant language switcher.

Homepage

License

MIT (license)

Dependencies

flutter, http, shared_preferences

More

Packages that depend on dynamic_app_translator