23 changed files with 747 additions and 280 deletions
@ -0,0 +1,87 @@ |
|||
import 'dart:io'; |
|||
import 'dart:ui'; |
|||
import 'package:flutter/services.dart'; |
|||
import 'package:get/get.dart'; |
|||
import '../translations/app_translations.dart'; |
|||
|
|||
class NativeLocalizationSync { |
|||
static const MethodChannel _channel = |
|||
MethodChannel('com.saitong.voitrans/native_localization'); |
|||
|
|||
static const List<String> nativeKeys = <String>[ |
|||
'native.notification.appName', |
|||
'native.notification.navigation.title', |
|||
'native.notification.navigation.keepRunning', |
|||
'native.notification.bleAgent.running', |
|||
'native.notification.audioRecording.recording', |
|||
'native.notification.music.waiting', |
|||
'native.notification.music.previous', |
|||
'native.notification.music.next', |
|||
'native.notification.music.play', |
|||
'native.notification.music.pause', |
|||
'native.notification.qqMusic.playing', |
|||
'unknownSong', |
|||
'unknownArtist', |
|||
]; |
|||
|
|||
static String? _lastLocaleKey; |
|||
static int? _lastPayloadHash; |
|||
static bool _isSyncing = false; |
|||
|
|||
static Future<void> syncToNative({bool force = false}) async { |
|||
if (!Platform.isAndroid) return; |
|||
if (_isSyncing) return; |
|||
|
|||
final Locale locale = Get.locale ?? |
|||
AppTranslations.deviceLocale() ?? |
|||
AppTranslations.fallbackLocale; |
|||
final String localeKey = _toAppTranslationsLocaleKey(locale); |
|||
|
|||
final Map<String, String> payload = _buildPayload(localeKey); |
|||
final int payloadHash = Object.hashAll( |
|||
payload.entries.map((e) => Object.hash(e.key, e.value)), |
|||
); |
|||
|
|||
if (!force && |
|||
_lastLocaleKey == localeKey && |
|||
_lastPayloadHash == payloadHash) { |
|||
return; |
|||
} |
|||
|
|||
_isSyncing = true; |
|||
try { |
|||
await _channel.invokeMethod('updateNativeStrings', <String, dynamic>{ |
|||
'locale': localeKey, |
|||
'strings': payload, |
|||
}); |
|||
_lastLocaleKey = localeKey; |
|||
_lastPayloadHash = payloadHash; |
|||
} finally { |
|||
_isSyncing = false; |
|||
} |
|||
} |
|||
|
|||
static Map<String, String> _buildPayload(String localeKey) { |
|||
final Map<String, Map<String, String>> all = AppTranslations().keys; |
|||
final Map<String, String>? current = all[localeKey]; |
|||
final Map<String, String>? fallback = |
|||
all['en_US'] ?? all[AppTranslations.fallbackLocale.toString()]; |
|||
|
|||
final Map<String, String> result = <String, String>{}; |
|||
for (final String key in nativeKeys) { |
|||
final String? value = current?[key] ?? fallback?[key]; |
|||
if (value == null || value.isEmpty) continue; |
|||
result[key] = value; |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
static String _toAppTranslationsLocaleKey(Locale locale) { |
|||
final String language = locale.languageCode; |
|||
final String? country = locale.countryCode; |
|||
if (country == null || country.isEmpty) { |
|||
return language.toLowerCase(); |
|||
} |
|||
return '${language.toLowerCase()}_${country.toUpperCase()}'; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue