Add localization support and translation script

- Introduced a new extension for localization in Flutter with `LocalizationExtension` in `l10n.dart`.
- Added a Python script `translate.py` for translating ARB/JSON localization files using a local Ollama model, preserving keys and placeholders, and handling ICU format rules.
This commit is contained in:
zjs81
2026-01-11 17:13:50 -07:00
parent 2495cd840f
commit b2ce82fe7e
64 changed files with 54716 additions and 1254 deletions
+22 -12
View File
@@ -1,5 +1,6 @@
import 'dart:typed_data';
import 'package:flutter/material.dart';
import '../l10n/l10n.dart';
import '../connector/meshcore_protocol.dart';
/// Debug widget to show the hex dump of a frame
@@ -10,23 +11,32 @@ class DebugFrameViewer {
.join(' ');
final details = StringBuffer();
details.writeln('Frame Length: ${frame.length} bytes\n');
details.writeln('Command: 0x${frame[0].toRadixString(16).padLeft(2, '0')}');
details.writeln(context.l10n.debugFrame_length(frame.length));
details.writeln('');
details.writeln(
context.l10n.debugFrame_command(frame[0].toRadixString(16).padLeft(2, '0')),
);
if (frame[0] == cmdSendTxtMsg && frame.length > 37) {
details.writeln('\nText Message Frame:');
details.writeln('- Destination PubKey: ${pubKeyToHex(frame.sublist(1, 33))}');
details.writeln('- Timestamp: ${readUint32LE(frame, 33)}');
details.writeln('- Flags: 0x${frame[37].toRadixString(16).padLeft(2, '0')}');
details.writeln('');
details.writeln(context.l10n.debugFrame_textMessageHeader);
details.writeln(context.l10n.debugFrame_destinationPubKey(pubKeyToHex(frame.sublist(1, 33))));
details.writeln(context.l10n.debugFrame_timestamp(readUint32LE(frame, 33)));
details.writeln(
context.l10n.debugFrame_flags(frame[37].toRadixString(16).padLeft(2, '0')),
);
final txtType = (frame[37] >> 2) & 0x03;
details.writeln('- Text Type: $txtType ${txtType == txtTypeCliData ? "(CLI)" : "(Plain)"}');
final typeLabel = txtType == txtTypeCliData
? context.l10n.debugFrame_textTypeCli
: context.l10n.debugFrame_textTypePlain;
details.writeln(context.l10n.debugFrame_textType(txtType, typeLabel));
if (frame.length > 38) {
final textBytes = frame.sublist(38);
final nullIdx = textBytes.indexOf(0);
final text = String.fromCharCodes(
nullIdx >= 0 ? textBytes.sublist(0, nullIdx) : textBytes
);
details.writeln('- Text: "$text"');
details.writeln(context.l10n.debugFrame_text(text));
}
}
@@ -44,9 +54,9 @@ class DebugFrameViewer {
style: const TextStyle(fontFamily: 'monospace', fontSize: 12),
),
const Divider(),
const Text(
'Hex Dump:',
style: TextStyle(fontWeight: FontWeight.bold),
Text(
context.l10n.debugFrame_hexDump,
style: const TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
@@ -59,7 +69,7 @@ class DebugFrameViewer {
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Close'),
child: Text(context.l10n.common_close),
),
],
),