Files
citypulse/lib/l10n/i18n.dart
Zahar 6518df8ac1 feat: introduce FixMate Flutter app and React dashboard
- 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
2025-09-25 18:38:18 +08:00

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;
}
}