- Add Flutter app shell (FixMateApp/MainScreen) with tabs: Report, Map, My Reports, Settings - Implement capture and review flow (image_picker, geolocator, deterministic mock AI), and local storage (SharedPreferences + photo files on mobile) - Build Map screen with flutter_map, marker clustering, filters, legend, marker details, and external maps deeplink - Add My Reports list (view details, cycle status, delete) and Settings (language toggle via Provider, diagnostics, clear all data) - Introduce JSON i18n loader and LocaleProvider; add EN/BM assets - Define models (Report, enums) and UI badges (severity, status) - Add static React dashboard (Leaflet map with clustering, heatmap toggle, filters incl. date range, queue, detail drawer), i18n (EN/BM), and demo data - Update build/config and platform setup: - Extend pubspec with required packages and register i18n assets - Android: add CAMERA and location permissions; pin NDK version - iOS: add usage descriptions for camera, photo library, location - Gradle properties tuned for Windows/UNC stability - Register desktop plugins (Linux/macOS/Windows) - .gitignore: ignore .kilocode - Overhaul README and replace sample widget test
79 lines
2.4 KiB
Dart
79 lines
2.4 KiB
Dart
import 'dart:convert';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart' show rootBundle;
|
|
|
|
/// Simple JSON-based internationalization service
|
|
class I18n {
|
|
static Map<String, String> _localizedStrings = {};
|
|
static const String _defaultLocale = 'en';
|
|
static String _loadedLocale = _defaultLocale;
|
|
|
|
/// Initialize the i18n system with the given locale
|
|
static Future<void> init(Locale locale) async {
|
|
_loadedLocale = locale.languageCode;
|
|
await _loadLanguage(locale.languageCode);
|
|
}
|
|
|
|
/// Load language strings from JSON asset
|
|
static Future<void> _loadLanguage(String languageCode) async {
|
|
try {
|
|
final String jsonString = await rootBundle.loadString(
|
|
'assets/lang/$languageCode.json',
|
|
);
|
|
final Map<String, dynamic> jsonMap = json.decode(jsonString);
|
|
|
|
_localizedStrings = jsonMap.map((key, value) {
|
|
return MapEntry(key, value.toString());
|
|
});
|
|
} catch (e) {
|
|
// Fallback to default locale if current locale fails
|
|
// ignore: avoid_print
|
|
print('Error loading language file for $languageCode: $e');
|
|
if (languageCode != _defaultLocale) {
|
|
_loadedLocale = _defaultLocale;
|
|
await _loadLanguage(_defaultLocale);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Get translated string for the given key
|
|
static String t(String key, [Map<String, String>? args]) {
|
|
String? translation = _localizedStrings[key];
|
|
|
|
if (translation == null) {
|
|
// Fallback to key itself if translation not found
|
|
// ignore: avoid_print
|
|
print('Translation key not found: $key');
|
|
return key;
|
|
}
|
|
|
|
// Replace placeholders if arguments provided
|
|
if (args != null && args.isNotEmpty) {
|
|
args.forEach((placeholder, value) {
|
|
translation = translation!.replaceAll('{$placeholder}', value);
|
|
});
|
|
}
|
|
|
|
return translation!;
|
|
}
|
|
|
|
/// Get the current locale code
|
|
static String get currentLocale => _loadedLocale;
|
|
|
|
/// Check if a translation key exists
|
|
static bool hasKey(String key) {
|
|
return _localizedStrings.containsKey(key);
|
|
}
|
|
|
|
/// Get all available translation keys
|
|
static Set<String> get keys => _localizedStrings.keys.toSet();
|
|
|
|
/// Get the number of loaded translations
|
|
static int get translationCount => _localizedStrings.length;
|
|
|
|
/// Clear loaded translations (useful for testing)
|
|
static void clear() {
|
|
_localizedStrings.clear();
|
|
_loadedLocale = _defaultLocale;
|
|
}
|
|
} |