Skip to content

Commit f970700

Browse files
committed
feat: integrate gettext for localization in chore management and UI
- Added gettext localization support in various components including ChoreManagerImpl, CoapOtaService, and Dashboard tiles. - Updated chore names to be translatable using gettext. - Refactored existing code to utilize context.translate for UI strings. - Removed hardcoded strings in favor of localized versions for better internationalization. - Bumped version to 0.5.3 to reflect changes.
1 parent 6f8ad59 commit f970700

16 files changed

Lines changed: 1459 additions & 1086 deletions

File tree

client/assets/i18n/de.po

Lines changed: 314 additions & 218 deletions
Large diffs are not rendered by default.

client/assets/i18n/en_US.po

Lines changed: 271 additions & 203 deletions
Large diffs are not rendered by default.

client/assets/i18n/es.po

Lines changed: 289 additions & 212 deletions
Large diffs are not rendered by default.

client/assets/i18n/messages.pot

Lines changed: 271 additions & 203 deletions
Large diffs are not rendered by default.

client/assets/i18n/zh_CN.po

Lines changed: 275 additions & 205 deletions
Large diffs are not rendered by default.

client/lib/app/app.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import 'package:borneo_kernel_abstractions/kernel.dart';
1313
import 'package:event_bus/event_bus.dart';
1414
import 'package:flutter/material.dart';
1515
import 'package:flutter/services.dart';
16+
import 'package:flutter_gettext/flutter_gettext.dart';
1617
import 'package:flutter_gettext/flutter_gettext/gettext_localizations.dart';
1718
import 'package:logger/logger.dart';
1819
import 'package:provider/provider.dart';
@@ -223,8 +224,10 @@ class _BorneoAppState extends State<BorneoApp> {
223224
context.read<IDeviceManager>(),
224225
clock: context.read<IClock>(),
225226
logger: context.read<Logger>(),
227+
gettext: gt,
226228
),
227229
dispose: (context, rm) => rm.dispose(),
230+
lazy: true,
228231
),
229232
],
230233
child: ToastificationWrapper(

client/lib/core/services/chore_manager_impl.dart

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import 'package:borneo_app/features/chores/models/builtin_chores.dart';
77
import 'package:borneo_app/core/services/devices/device_manager.dart';
88
import 'package:borneo_app/core/services/chore_history_store.dart';
99
import 'package:event_bus/event_bus.dart';
10+
import 'package:flutter_gettext/flutter_gettext.dart';
1011
import 'package:logger/logger.dart';
1112
import 'package:sembast/sembast.dart';
1213
import 'package:synchronized/synchronized.dart';
1314

1415
final class ChoreManagerImpl implements IChoreManager {
16+
final GettextLocalizations gettext;
1517
final Logger? logger;
1618
final IClock clock;
1719

@@ -36,9 +38,15 @@ final class ChoreManagerImpl implements IChoreManager {
3638
this._sceneManager,
3739
this._deviceManager, {
3840
required this.clock,
41+
required this.gettext,
3942
this.logger,
4043
}) : _historyStore = ChoreHistoryStore(_db) {
41-
allChores.addAll([PowerOffAllChore(), FeedModeChore(), WaterChangeModeChore(), DryScapeModeChore()]);
44+
allChores.addAll([
45+
PowerOffAllChore(name: gettext.translate('Power Off All')),
46+
FeedModeChore(name: gettext.translate('Feed Mode')),
47+
WaterChangeModeChore(name: gettext.translate('Water Change Mode')),
48+
DryScapeModeChore(name: gettext.translate('Dry Scape Mode')),
49+
]);
4250

4351
// Subscribe to device reload events and publish a ChoresChangedEvent so UI can refresh
4452
_globalBus.on<CurrentSceneDevicesReloadedEvent>().listen((event) {

client/lib/core/services/devices/ota_providers.dart

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:borneo_kernel_abstractions/kernel.dart';
55
import 'package:cancellation_token/cancellation_token.dart';
66
import 'package:crypto/crypto.dart';
77
import 'package:flutter/foundation.dart';
8+
import 'package:flutter_gettext/flutter_gettext.dart';
89
import 'package:http/http.dart' as http;
910
import 'package:libcompress/libcompress.dart';
1011
import 'package:logger/logger.dart';
@@ -38,15 +39,19 @@ abstract class IOtaService {
3839

3940
final class CoapOtaService implements IOtaService {
4041
final Logger? _logger;
42+
final GettextLocalizations gt;
4143

42-
CoapOtaService({Logger? logger}) : _logger = logger;
44+
CoapOtaService({required this.gt, Logger? logger}) : _logger = logger;
4345

4446
/// Fetches the manifest JSON and returns the entry whose `product_id` and
4547
/// `compatible` both match the given values. Returns `null` if not found.
4648
Future<Map<String, dynamic>?> _fetchMatchingManifestEntry(String productId, String compatible) async {
4749
final response = await http.get(Uri.parse(_kManifestUrl));
4850
if (response.statusCode != 200) {
49-
final msg = 'Failed to fetch firmware manifest: HTTP ${response.statusCode}';
51+
final msg = gt.translate(
52+
'Failed to fetch firmware manifest: HTTP code `{code}`',
53+
nArgs: {'code': response.statusCode},
54+
);
5055
_logger?.e(msg);
5156
throw StateError(msg);
5257
}
@@ -72,7 +77,7 @@ final class CoapOtaService implements IOtaService {
7277

7378
final entry = await _fetchMatchingManifestEntry(localProductId, localCompatible);
7479
if (entry == null) {
75-
final msg = 'No firmware entry found for product_id=$localProductId compatible=$localCompatible';
80+
final msg = gt.translate('No firmware entry found for product ID `{pid}`', nArgs: {'pid': localProductId});
7681
_logger?.w(msg);
7782
throw StateError(msg);
7883
}
@@ -122,7 +127,7 @@ final class CoapOtaService implements IOtaService {
122127
// Step 3: Verify SHA256 of compressed file
123128
final digest = sha256.convert(compressedData);
124129
if (digest.toString() != upgradeInfo.otaSha256) {
125-
final msg = 'Firmware SHA256 mismatch: expected ${upgradeInfo.otaSha256}, got $digest';
130+
final msg = gt.translate('Firmware hash mismatch');
126131
_logger?.e(msg);
127132
throw StateError(msg);
128133
}
@@ -142,8 +147,8 @@ final class OtaProvider {
142147
static const String kCoapType = 'coap';
143148
const OtaProvider();
144149

145-
IOtaService create({String type = kCoapType, Logger? logger}) => switch (type) {
146-
kCoapType => CoapOtaService(logger: logger),
150+
IOtaService create({String type = kCoapType, required GettextLocalizations gt, Logger? logger}) => switch (type) {
151+
kCoapType => CoapOtaService(logger: logger, gt: gt),
147152
_ => throw Error(),
148153
};
149154
}

client/lib/devices/borneo/lyfi/views/dashboard/dashboard_power_switch_tile.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:flutter/material.dart';
2+
import 'package:flutter_gettext/flutter_gettext.dart';
23
import 'package:provider/provider.dart';
34

45
import 'package:borneo_app/features/devices/widgets/dashboard_tile.dart';
@@ -70,7 +71,7 @@ class DashboardPowerSwitchTile extends StatelessWidget {
7071
crossAxisAlignment: CrossAxisAlignment.start,
7172
children: [
7273
Text(
73-
isOn ? 'ON' : 'OFF',
74+
isOn ? context.translate('ON') : context.translate('OFF'),
7475
style: theme.textTheme.titleSmall?.copyWith(
7576
color: isDisabled ? disabledColor : (isOn ? theme.colorScheme.onSurface : Colors.red),
7677
fontWeight: FontWeight.bold,

client/lib/devices/borneo/lyfi/views/dashboard/dashboard_settings_tile.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class DashboardSettingsTile extends StatelessWidget {
3232

3333
Widget tile = DashboardTile(
3434
disabled: isDisabled,
35-
onPressed: isDisabled ? null : () => _openSettings(context, gt),
35+
onPressed: isDisabled ? null : () async => await _openSettings(context, gt),
3636
child: Badge(
3737
key: Key('settings_red_dot'),
3838
largeSize: 12,

0 commit comments

Comments
 (0)