简单的本地化翻译无法始终如一地工作,有时它无法翻译整个应用程序,为什么会出现此问题?

问题描述 投票:0回答:1

这是用于从 api 获取 Translation.json 文件的资产加载器类。

class SmartNetworkAssetLoader extends AssetLoader {
  final Function localeUrl;

  final Duration timeout;

  final String assetsPath;

  final Duration localCacheDuration;

  SmartNetworkAssetLoader(
      {required this.localeUrl,
        this.timeout = const Duration(seconds: 30),
        required this.assetsPath,
        this.localCacheDuration = const Duration(days: 1)});

  @override
  Future<Map<String, dynamic>> load(String localePath, Locale locale) async {
    var string = '';
     print("localPath $localePath");
     print("locale $locale");
    // try loading local previously-saved localization file
    if (await localTranslationExists(locale.toString())) {
      string = await loadFromLocalFile(locale.toString());
    }

    // no local or failed, check if internet and download the file
    if (string == '' && await isInternetConnectionAvailable()) {
      string = await loadFromNetwork(locale.toString());
    }

    // local cache duration was reached or no internet access but prefer local file to assets
    if (string == '' &&
        await localTranslationExists(locale.toString(),
            ignoreCacheDuration: false)) {
      string = await loadFromLocalFile(locale.toString());
    }

    // still nothing? Load from assets
    if (string == '') {
      String localeString = locale.toString();

      // Replace underscores with hyphens
      String convertedLocale = localeString.replaceAll('_', '-');
      string = await rootBundle
          .loadString('$assetsPath/$convertedLocale.json');
    }

    // then returns the json file
    return json.decode(string);
  }

  Future<bool> localeExists(String localePath) => Future.value(true);

  Future<bool> isInternetConnectionAvailable() async {
    try{
      ConnectivityResult connectivityResult =
      await (Connectivity().checkConnectivity());
      if (connectivityResult == ConnectivityResult.none) return false;

      final result = await Future.any(
          [InternetAddress.lookup('google.com'), Future.delayed(timeout)]);

      if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
        return true;
      }

    }catch(e)
    {
     print(e);
    }
    return false;
  }

  Future<String> loadFromNetwork(String localeName) async {
    String url = localeUrl(localeName);
     print("loccaleName$localeName");
     print("url $url");
    url = '$url$localeName';
     print("final Url $url");
    try {
      final response =
      await Future.any([http.get(Uri.parse(url)), Future.delayed(timeout)]);

      if (response != null && response.statusCode == 200) {
        var content = utf8.decode(response.bodyBytes);
        log("content1234 $content");
        try {
          var jsonResponse = json.decode(content);
          if (jsonResponse != null && jsonResponse['data'] != null) {
            // Extract only the "data" content
            var dataContent = jsonResponse['data'];
            // Convert it back to a JSON string
            var dataContentString = json.encode(dataContent);
            print("data content: $dataContentString");
            print("localeName $localeName");
            // Save the translation
            await saveTranslation(localeName, dataContentString);
            return dataContentString;
          }
        } catch (e) {
          showFalseSnackbar("$e");
          print("Error decoding JSON: $e");
        }
      }else{
        showFalseSnackbar("response null or ${response.statusCode}");
      }
    } catch (e) {
      showFalseSnackbar("$e");
      print(e.toString());
    }

    return '';
  }

  Future<bool> localTranslationExists(String localeName,
      {bool ignoreCacheDuration = false}) async {
    var translationFile = await getFileForLocale(localeName);

    if (!await translationFile.exists()) {
      return false;
    }

    // don't check file's age
    if (!ignoreCacheDuration) {
      var difference =
      DateTime.now().difference(await translationFile.lastModified());

      if (difference > (localCacheDuration)) {
        return false;
      }
    }

    return true;
  }

  Future<String> loadFromLocalFile(String localeName) async {
    return await (await getFileForLocale(localeName)).readAsString();
  }

  Future<void> saveTranslation(String localeName, String content) async {
    try{
      var file = File(await getFilenameForLocale(localeName));
      await file.create(recursive: true);
      return print('saved');
    }catch(e)
    {
     print("error creating file $e");
    }

  }

  Future<String> get _localPath async {
    final directory = await paths.getTemporaryDirectory();

    return directory.path;
  }

  Future<String> getFilenameForLocale(String localeName) async {
    return '${await _localPath}/translations/$localeName.json';
  }

  Future<File> getFileForLocale(String localeName) async {
    return File(await getFilenameForLocale(localeName));
  }
}

main.dart 文件代码

runApp((EasyLocalization(
        supportedLocales:[
        Locale('en', 'US'),
        Locale('es', 'ES')
         ],
        path: 'assets/translations',
        fallbackLocale: const Locale('en', 'US'),
        assetLoader:  SmartNetworkAssetLoader(
          assetsPath: 'assets/translations',
          localCacheDuration: const Duration(days: 1),
          localeUrl: (String localeName) => Constants.appLangUrl,
          timeout: const Duration(seconds: 30),
        ),
        child: const MyApp())));

更改功能时下拉。

DropdownButton<String>(
                              value: state.selectedValue,
                              onChanged: (newValue) async {
                                context.read<LoginBloc>().add(DropDownButtonClickedEvent(newValue!));
                                await changeLanguageHandler(context, newValue);
                              },
                              items: state.list
                                  ?.map<DropdownMenuItem<String>>((element) {
                                return DropdownMenuItem<String>(
                                  value: element,
                                  child: Text(
                                    element,
                                    style: const TextStyle(
                                      color: Colors.white,
                                      fontSize: 18,
                                      fontWeight: FontWeight.w400,
                                    ),
                                  ),
                                );
                              }).toList(),
                              icon: Image.asset(
                                "assets/images/arrowdown.png",
                                width: 16.w,
                                height: 7.h,
                              ),
                            ),

在下拉菜单上单击将调用以下函数。

Future<void> changeLanguageHandler( BuildContext context, String language) async {
            try {
      await LocalizationChecker.changeLanguage(context, language);
      setState(() {});
     
    } catch (error) {
      print("error $error");
    }
  }
class LocalizationChecker {
  static changeLanguage(BuildContext context, String language) {
    // Locale? currentLocal = EasyLocalization.of(context)!.currentLocale;
    print("inside localization");
    if (language == 'Spanish') {
      EasyLocalization.of(context)!.setLocale(const Locale('es', 'ES'));
    } else {
      EasyLocalization.of(context)!.setLocale(const Locale('en', 'US'));
    }
  }
}

这里我的主要问题是,当我们通过 api 调用(SmartAssetLoader 类)使用时,翻译工作不一致,为什么会发生这种情况,我的 smartassetloader 类上有什么问题吗? 或任何库问题。在这里,为了通过 api 调用更改翻译,我们使用名为 easy_localization_loader 2.0.1 和 easy_localization 3.0.3 的库,请帮助我,我是新手。

flutter dart localization flutter-localizations flutter-easy-localization
1个回答
0
投票

您的

SmartNetworkAssetLoader
(来自 easy_localization
AssetLoader
)检查本地翻译,然后网络,再次本地,最后尝试资产(!)。如果任何步骤出现意外行为,那么复杂的逻辑可能会导致问题。特别是,网络加载部分可能会默默地失败:网络问题可能会导致翻译加载不一致。如果网络请求失败或超时,加载器将回退到本地或基于资产的翻译。

另外,您的

saveTranslation
函数会创建一个文件,但实际上并未将内容写入其中。这意味着您的本地翻译可能永远不会真正保存。

修改

SmartNetworkAssetLoader
类,包括简化加载逻辑、增强错误处理和日志记录、检查网络可靠性以及修复文件保存逻辑。

class SmartNetworkAssetLoader extends AssetLoader {
  final Function localeUrl;
  final Duration timeout;
  final String assetsPath;
  final Duration localCacheDuration;

  SmartNetworkAssetLoader({
    required this.localeUrl,
    this.timeout = const Duration(seconds: 30),
    required this.assetsPath,
    this.localCacheDuration = const Duration(days: 1),
  });

  @override
  Future<Map<String, dynamic>> load(String localePath, Locale locale) async {
    var string = '';
    var localeString = locale.toString();

    try {
      // Check local cache first
      if (await localTranslationExists(localeString)) {
        string = await loadFromLocalFile(localeString);
      }

      // If not in local cache or cache is outdated, try to load from network
      if (string.isEmpty && await isInternetConnectionAvailable()) {
        string = await loadFromNetwork(localeString);
      }

      // If still not loaded, use assets as a fallback
      if (string.isEmpty) {
        string = await loadFromAssets(localeString);
      }

      // Parse and return the JSON
      return json.decode(string);
    } catch (e) {
      print("Error loading translation: $e");
      // Fallback to loading from assets in case of any error
      return json.decode(await loadFromAssets(localeString));
    }
  }

  Future<String> loadFromAssets(String localeString) async {
    String convertedLocale = localeString.replaceAll('_', '-');
    return await rootBundle.loadString('$assetsPath/$convertedLocale.json');
  }

  // Rest of the methods remain the same
}

// Make sure the saveTranslation method writes the content to the file
Future<void> saveTranslation(String localeName, String content) async {
  try {
    var file = File(await getFilenameForLocale(localeName));
    await file.create(recursive: true);
    await file.writeAsString(content); // Write content to the file
    print('Translation saved for $localeName');
  } catch (e) {
    print("Error saving translation for $localeName: $e");
  }
}

该函数现在首先检查本地翻译,然后检查网络,最后返回到资产。这简化了流程。加载器现在可以捕获加载过程中的任何异常,记录它们,并在需要时回退到资产。

现有的网络检查逻辑保持不变,但任何网络加载失败都会导致立即回退到资产。
并且

saveTranslation
函数现在可以正确地将内容写入文件。

© www.soinside.com 2019 - 2024. All rights reserved.