这是用于从 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 的库,请帮助我,我是新手。
您的
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
函数现在可以正确地将内容写入文件。