downloadLanguageFiles method

Future<void> downloadLanguageFiles(
  1. String baseUrl,
  2. List<String> languageCodes, {
  3. Map<String, String>? headers,
  4. Map<String, dynamic>? queryParameters,
})

Downloads the latest language files from a remote URL for dynamic updates.

This method allows the application to download and cache translation files from a remote server, enabling dynamic language updates without app updates. Downloaded files are stored in the application's documents directory.

The method downloads files for each language code in the list and updates the internal translation cache. If a download fails for a particular language, the method continues with the remaining languages.

baseUrl is the base URL for translation files (e.g., 'https://api.example.com/translations'). languageCodes is the list of language codes to download (e.g., 'en', 'es', 'fr').

Files are expected to be available at {baseUrl}/{languageCode}.json.

Throws Exception if the download process fails completely.

Example:

await PWLocalizationService.instance.downloadLanguageFiles(
  'https://api.example.com/translations',
  ['en', 'es', 'fr'],
);

Implementation

Future<void> downloadLanguageFiles(
  String baseUrl,
  List<String> languageCodes, {
  Map<String, String>? headers,
  Map<String, dynamic>? queryParameters,
}) async {
  try {
    if (_downloadedPath.isEmpty) {
      throw Exception(
        'PWLocalizationService must be initialized before downloading.',
      );
    }

    final appDir = await getApplicationDocumentsDirectory();
    final translationsDir = '${appDir.path}/$_downloadedPath';

    // Create translations directory if it doesn't exist
    final dir = Directory(translationsDir);
    if (!await dir.exists()) {
      await dir.create(recursive: true);
    }

    var successCount = 0;
    final failures = <String, Object>{};

    for (final raw in languageCodes) {
      final localeTag = normalizeLocaleTag(raw);

      try {
        if (_assetTranslations[raw] == null) {
          _assetTranslations[raw] = await _loadAssetTranslations(raw);
        }

        final url = baseUrl.endsWith('/')
            ? '$baseUrl$localeTag.json'
            : '$baseUrl/$localeTag.json';
        final response = await _dio.get(
          url,
          options: Options(
            responseType: ResponseType.plain,
            headers: headers,
          ),
          queryParameters: queryParameters,
        );

        if (response.statusCode == 200) {
          final filePath = '$translationsDir/$localeTag.json';
          final file = File(filePath);

          // Delete existing file if it exists
          if (await file.exists()) {
            await file.delete();
          }

          final data = response.data;

          // Persist **valid JSON** only.
          if (data is String) {
            json.decode(data); // validate
            await file.writeAsString(data);
          } else if (data is Map || data is List) {
            await file.writeAsString(jsonEncode(data));
          } else {
            throw Exception('Unexpected response type: ${data.runtimeType}');
          }

          successCount++;

          // Reload translations if this is the current locale
          final currentTag = _currentLocaleTag;
          if (currentTag != null) {
            final currentLanguageCode = tagToLanguageCode(currentTag);
            if (localeTag == currentTag || localeTag == currentLanguageCode) {
              _translations[currentTag] = await _loadDownloadedTranslations(
                currentTag,
              );
              notifyListeners();
            }
          }
        } else {
          failures[localeTag] = 'HTTP ${response.statusCode} for $url';
        }
      } catch (e) {
        failures[localeTag] = e;
        debugPrint(
          '[PWLocalizationService] Download failed for "$localeTag": $e',
        );
      }
    }

    if (successCount == 0 && failures.isNotEmpty) {
      throw Exception(
        'Failed to download any language files. Failures: $failures',
      );
    }
  } catch (e) {
    throw Exception('Failed to download language files: $e');
  }
}