如何借助自有翻译API实现Flutter应用的本地化?
Got it, let's walk through how to hook up your custom translation API to handle localization in your Flutter app. I'll break this down into actionable steps that fit with Flutter's localization system, plus we'll work with the API response format you shared.
1. Build a Core Translation Service
First, create a dedicated service class to handle API calls, parse responses, and manage translated strings. This keeps your API logic clean and separate from the UI layer.
You'll need the http package first—add it to your pubspec.yaml under dependencies:
dependencies: flutter: sdk: flutter http: ^1.1.0
Here's the service implementation tailored to your API response:
import 'dart:convert'; import 'package:http/http.dart' as http; class TranslationService { final String apiBaseUrl; TranslationService(this.apiBaseUrl); // Fetch translations for a target locale Future<Map<String, String>> fetchTranslations(String locale) async { try { final response = await http.post( Uri.parse('$apiBaseUrl/translate'), // Adjust to your actual endpoint body: {'target_locale': locale}, // Send locale as a request parameter ); if (response.statusCode == 200) { final data = json.decode(response.body); // Parse your API's specific response structure if (data['status'] == 'success' && data['result'] is List) { final translations = <String, String>{}; // Merge all translation objects from the result list into one map for (final item in data['result']) { if (item is Map<String, dynamic>) { translations.addAll(item.cast<String, String>()); } } return translations; } else { throw Exception('Failed to parse translation response'); } } else { throw Exception('API request failed with status: ${response.statusCode}'); } } catch (e) { print('Translation API error: $e'); // Fallback to default strings if API call fails return {'hello': 'hello'}; } } }
2. Create a Custom Localization Delegate
Flutter uses LocalizationsDelegate to load localized strings. We'll build a custom delegate that uses our TranslationService to fetch strings from the API.
import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; class AppLocalizations { final Map<String, String> translations; AppLocalizations(this.translations); // Helper method to get translated strings by key String translate(String key) { return translations[key] ?? key; // Return key if translation is missing } // Static method to access translations from any widget context static AppLocalizations of(BuildContext context) { return Localizations.of<AppLocalizations>(context, AppLocalizations)!; } } class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> { final TranslationService translationService; final List<Locale> supportedLocales; AppLocalizationsDelegate({ required this.translationService, required this.supportedLocales, }); @override bool isSupported(Locale locale) { // Check if the locale is in our supported list return supportedLocales.any((l) => l.languageCode == locale.languageCode); } @override Future<AppLocalizations> load(Locale locale) async { // Fetch translations for the current locale final translations = await translationService.fetchTranslations(locale.languageCode); return AppLocalizations(translations); } @override bool shouldReload(covariant LocalizationsDelegate<AppLocalizations> old) { // Return true if you want to reload translations when the app state changes return false; } }
3. Integrate with Your Flutter App
Wire up the delegate and service in your main app widget to make translations available across your app:
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { // Initialize your translation service with your API base URL final translationService = TranslationService('https://your-api-domain.com'); // Define locales your API supports final supportedLocales = const [ Locale('en'), Locale('es'), Locale('fr'), // Add more locales as needed ]; return MaterialApp( title: 'Custom Localization Demo', localizationsDelegates: [ AppLocalizationsDelegate( translationService: translationService, supportedLocales: supportedLocales, ), // Keep default delegates for system widgets (date pickers, etc.) GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: supportedLocales, home: const HomeScreen(), ); } } class HomeScreen extends StatelessWidget { const HomeScreen({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(AppLocalizations.of(context).translate('hello'))), body: Center( child: Text(AppLocalizations.of(context).translate('hello')), ), ); } }
4. Add Caching (Critical for Performance)
Calling the API every time the app loads or the locale changes isn't efficient. Add a caching layer using shared_preferences to store fetched translations locally.
First add shared_preferences to your pubspec.yaml:
dependencies: # ... other dependencies shared_preferences: ^2.2.2
Update the TranslationService to include caching:
import 'package:shared_preferences/shared_preferences.dart'; class TranslationService { final String apiBaseUrl; late SharedPreferences _prefs; TranslationService(this.apiBaseUrl) { _initPrefs(); } Future<void> _initPrefs() async { _prefs = await SharedPreferences.getInstance(); } Future<Map<String, String>> fetchTranslations(String locale) async { // Check cache first final cachedTranslations = _prefs.getString('translations_$locale'); if (cachedTranslations != null) { return Map<String, String>.from(json.decode(cachedTranslations)); } // If no cache, call API try { final response = await http.post( Uri.parse('$apiBaseUrl/translate'), body: {'target_locale': locale}, ); if (response.statusCode == 200) { final data = json.decode(response.body); if (data['status'] == 'success' && data['result'] is List) { final translations = <String, String>{}; for (final item in data['result']) { if (item is Map<String, dynamic>) { translations.addAll(item.cast<String, String>()); } } // Save to cache for future use await _prefs.setString('translations_$locale', json.encode(translations)); return translations; } else { throw Exception('Failed to parse translation response'); } } else { throw Exception('API request failed with status: ${response.statusCode}'); } } catch (e) { print('Translation API error: $e'); return {'hello': 'hello'}; } } }
5. Handle Edge Cases
- API Failures: Always include fallback strings so your app doesn't break if the API is unavailable.
- Auto-Detect Locale: Use
window.locale(fromdart:ui) to automatically set the user's device locale on startup. - Dynamic Locale Switching: Add a settings screen to let users change locales, then use state management (like
ProviderorRiverpod) to reload localizations.
内容的提问来源于stack exchange,提问作者Nirav

