translate notifications.

This commit is contained in:
ericz
2026-05-10 11:09:25 +02:00
parent e92a66ff28
commit d2a6fbe182
2 changed files with 79 additions and 22 deletions
+78 -21
View File
@@ -4408,22 +4408,38 @@ class MeshCoreConnector extends ChangeNotifier {
_appSettingsService != null) { _appSettingsService != null) {
final settings = _appSettingsService!.settings; final settings = _appSettingsService!.settings;
if (settings.notificationsEnabled && settings.notifyOnNewMessage) { if (settings.notificationsEnabled && settings.notifyOnNewMessage) {
// Capture non-null local for async closure type promotion
final msg = message;
if (contact?.type == advTypeChat) { if (contact?.type == advTypeChat) {
_notificationService.showMessageNotification( unawaited(() async {
contactName: contact?.name ?? 'Unknown', final resolvedText = await _maybeTranslateForNotification(
message: message.text, msg.text,
contactId: message.senderKeyHex, isCli: msg.isCli,
badgeCount: getTotalUnreadCount(), );
); await _notificationService.showMessageNotification(
contactName: contact?.name ?? 'Unknown',
message: resolvedText,
contactId: msg.senderKeyHex,
badgeCount: getTotalUnreadCount(),
);
}());
} else if (contact?.type == advTypeRoom) { } else if (contact?.type == advTypeRoom) {
_notificationService.showMessageNotification( // Room server messages include a 4-char prefix; strip it for notifications
contactName: contact?.name ?? 'Unknown Room', final bodyText = msg.text.length > 4
message: message.text.length > 4 ? msg.text.substring(4)
? message.text.substring(4) : msg.text;
: message.text, unawaited(() async {
contactId: message.senderKeyHex, final resolvedText = await _maybeTranslateForNotification(
badgeCount: getTotalUnreadCount(), bodyText,
); isCli: msg.isCli,
);
await _notificationService.showMessageNotification(
contactName: contact?.name ?? 'Unknown Room',
message: resolvedText,
contactId: msg.senderKeyHex,
badgeCount: getTotalUnreadCount(),
);
}());
} }
} }
} }
@@ -4705,13 +4721,54 @@ class MeshCoreConnector extends ChangeNotifier {
final label = channelName ?? _channelDisplayName(channelIndex); final label = channelName ?? _channelDisplayName(channelIndex);
if (_appSettingsService!.isChannelMuted(label)) return; if (_appSettingsService!.isChannelMuted(label)) return;
_notificationService.showChannelMessageNotification( // Translate channel notification text if enabled
channelName: label, unawaited(() async {
senderName: message.senderName, final resolvedText = await _maybeTranslateForNotification(
message: message.text, message.text,
channelIndex: channelIndex, isCli: false,
badgeCount: getTotalUnreadCount(), );
); await _notificationService.showChannelMessageNotification(
channelName: label,
senderName: message.senderName,
message: resolvedText,
channelIndex: message.channelIndex,
badgeCount: getTotalUnreadCount(),
);
}());
}
Future<String> _maybeTranslateForNotification(
String text, {
required bool isCli,
}) async {
final service = _translationService;
if (service == null) return text;
try {
if (!service.shouldTranslateIncoming(
text: text,
isCli: isCli,
isOutgoing: false,
)) {
return text;
}
final targetLanguageCode = service.resolvedIncomingLanguageCode(
_appSettingsService?.settings.languageOverride,
);
if (targetLanguageCode == null || targetLanguageCode.isEmpty) {
return text;
}
final result = await service.translateIncomingText(
text: text,
targetLanguageCode: targetLanguageCode,
);
final translated = result?.translatedText.trim();
if (translated != null && translated.isNotEmpty) {
return translated;
}
} catch (_) {
// Fallback to original text on any error
}
return text;
} }
void _handleIncomingChannelMessage(Uint8List frame) { void _handleIncomingChannelMessage(Uint8List frame) {
+1 -1
View File
@@ -454,7 +454,7 @@ class TranslationService extends ChangeNotifier {
final targetLabel = _languageLabel(targetLanguageCode); final targetLabel = _languageLabel(targetLanguageCode);
final instruction = targetLanguageCode == 'zh' final instruction = targetLanguageCode == 'zh'
? '将以下文本翻译为中文,注意只需要输出翻译后的结果,不要额外解释:\n\n$text' ? '将以下文本翻译为中文,注意只需要输出翻译后的结果,不要额外解释:\n\n$text'
: 'Translate the following segment into $targetLabel, without additional explanation.\n\n$text'; : 'Translate the following segment into $targetLabel, without additional explanation. If it is already in $targetLabel, then return the exact same String.\n\n$text';
try { try {
return await _runExclusive(() async { return await _runExclusive(() async {
final engine = await _ensureContext(model.localPath); final engine = await _ensureContext(model.localPath);