diff --git a/.gitignore b/.gitignore index 41d85b945..abdaaa5b6 100644 --- a/.gitignore +++ b/.gitignore @@ -41,7 +41,7 @@ app.*.symbols app.*.map.json # Exceptions to above rules. -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages /ios/build/ /ios/Podfile.lock /ios/Runner/GoogleService-Info.plist @@ -56,3 +56,4 @@ app.*.map.json /test/ /linux/ .fvm +/assets/openl.json diff --git a/assets/openl.json.sample b/assets/openl.json.sample new file mode 100644 index 000000000..068d6a068 --- /dev/null +++ b/assets/openl.json.sample @@ -0,0 +1,4 @@ +// 填入自己的OpenL apikey (https://openl.club/), 并修改文件名为 openl.json +{ + "apikey": "abcabcacb" +} diff --git a/jsons/openl_translation.json b/jsons/openl_translation.json new file mode 100644 index 000000000..ff2517706 --- /dev/null +++ b/jsons/openl_translation.json @@ -0,0 +1,7 @@ +{ + "status?": true, + "text?": "HTML elements", + "result?": "HTML元素", + "source_lang?": "auto", + "target_lang?": "zh" +} \ No newline at end of file diff --git a/lib/models/dns_config.dart b/lib/models/dns_config.dart index ad01fb196..fe7e27c79 100644 --- a/lib/models/dns_config.dart +++ b/lib/models/dns_config.dart @@ -1,5 +1,5 @@ import 'package:flutter/foundation.dart'; - +import 'dns_cache.dart'; import 'dns_cache.dart'; @immutable diff --git a/lib/models/gallery_comment.dart b/lib/models/gallery_comment.dart index 7bf09324c..d4a76d031 100644 --- a/lib/models/gallery_comment.dart +++ b/lib/models/gallery_comment.dart @@ -1,5 +1,4 @@ import 'package:flutter/foundation.dart'; - import 'gallery_comment_span.dart'; @immutable diff --git a/lib/models/gallery_item.dart b/lib/models/gallery_item.dart index 1809d6d49..81ba9d46a 100644 --- a/lib/models/gallery_item.dart +++ b/lib/models/gallery_item.dart @@ -1,10 +1,9 @@ import 'package:flutter/foundation.dart'; - -import 'gallery_comment.dart'; -import 'gallery_preview.dart'; import 'gallery_torrent.dart'; import 'simple_tag.dart'; import 'tag_group.dart'; +import 'gallery_comment.dart'; +import 'gallery_preview.dart'; @immutable class GalleryItem { diff --git a/lib/models/index.dart b/lib/models/index.dart index e536b787e..c5cb49ca7 100644 --- a/lib/models/index.dart +++ b/lib/models/index.dart @@ -1,24 +1,25 @@ -export 'advance_search.dart'; -export 'auto_lock.dart'; -export 'cache_config.dart'; +export 'local_fav.dart'; +export 'eh_config.dart'; +export 'simple_tag.dart'; export 'commit_vote_res.dart'; -export 'dns_cache.dart'; -export 'dns_config.dart'; -export 'download_config.dart'; +export 'auto_lock.dart'; +export 'gallery_item.dart'; export 'download_task_info.dart'; -export 'eh_config.dart'; -export 'favcat.dart'; +export 'dns_config.dart'; export 'gallery_cache.dart'; -export 'gallery_comment.dart'; export 'gallery_comment_span.dart'; -export 'gallery_item.dart'; -export 'gallery_preview.dart'; +export 'gallery_comment.dart'; +export 'openl_translation.dart'; export 'gallery_tag.dart'; -export 'gallery_torrent.dart'; -export 'local_fav.dart'; -export 'profile.dart'; -export 'simple_tag.dart'; -export 'tab_config.dart'; +export 'dns_cache.dart'; export 'tab_item.dart'; -export 'tag_group.dart'; export 'user.dart'; +export 'download_config.dart'; +export 'gallery_torrent.dart'; +export 'advance_search.dart'; +export 'tag_group.dart'; +export 'tab_config.dart'; +export 'favcat.dart'; +export 'cache_config.dart'; +export 'gallery_preview.dart'; +export 'profile.dart'; diff --git a/lib/models/local_fav.dart b/lib/models/local_fav.dart index 476dd8811..c33626c6b 100644 --- a/lib/models/local_fav.dart +++ b/lib/models/local_fav.dart @@ -1,5 +1,4 @@ import 'package:flutter/foundation.dart'; - import 'gallery_item.dart'; @immutable diff --git a/lib/models/openl_translation.dart b/lib/models/openl_translation.dart new file mode 100644 index 000000000..948e56fed --- /dev/null +++ b/lib/models/openl_translation.dart @@ -0,0 +1,66 @@ +import 'package:flutter/foundation.dart'; + + +@immutable +class OpenlTranslation { + + const OpenlTranslation({ + this.status, + this.text, + this.result, + this.sourceLang, + this.targetLang, + }); + + final bool? status; + final String? text; + final String? result; + final String? sourceLang; + final String? targetLang; + + factory OpenlTranslation.fromJson(Map json) => OpenlTranslation( + status: json['status'] != null ? json['status'] as bool : null, + text: json['text'] != null ? json['text'] as String : null, + result: json['result'] != null ? json['result'] as String : null, + sourceLang: json['source_lang'] != null ? json['source_lang'] as String : null, + targetLang: json['target_lang'] != null ? json['target_lang'] as String : null + ); + + Map toJson() => { + 'status': status, + 'text': text, + 'result': result, + 'source_lang': sourceLang, + 'target_lang': targetLang + }; + + OpenlTranslation clone() => OpenlTranslation( + status: status, + text: text, + result: result, + sourceLang: sourceLang, + targetLang: targetLang + ); + + + OpenlTranslation copyWith({ + bool? status, + String? text, + String? result, + String? sourceLang, + String? targetLang + }) => OpenlTranslation( + status: status ?? this.status, + text: text ?? this.text, + result: result ?? this.result, + sourceLang: sourceLang ?? this.sourceLang, + targetLang: targetLang ?? this.targetLang, + ); + + @override + bool operator ==(Object other) => identical(this, other) + || other is OpenlTranslation && status == other.status && text == other.text && result == other.result && sourceLang == other.sourceLang && targetLang == other.targetLang; + + @override + int get hashCode => status.hashCode ^ text.hashCode ^ result.hashCode ^ sourceLang.hashCode ^ targetLang.hashCode; +} diff --git a/lib/models/tab_config.dart b/lib/models/tab_config.dart index ba6e9cb0f..fd922ef0e 100644 --- a/lib/models/tab_config.dart +++ b/lib/models/tab_config.dart @@ -1,5 +1,4 @@ import 'package:flutter/foundation.dart'; - import 'tab_item.dart'; @immutable diff --git a/lib/models/tag_group.dart b/lib/models/tag_group.dart index e9ac74479..0153321e1 100644 --- a/lib/models/tag_group.dart +++ b/lib/models/tag_group.dart @@ -1,5 +1,4 @@ import 'package:flutter/foundation.dart'; - import 'gallery_tag.dart'; @immutable diff --git a/lib/models/user.dart b/lib/models/user.dart index 9d7723203..d30002ff2 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -1,5 +1,4 @@ import 'package:flutter/foundation.dart'; - import 'favcat.dart'; @immutable diff --git a/lib/pages/gallery/view/translator_dialog.dart b/lib/pages/gallery/view/translator_dialog.dart index 51dbabc06..0bf280fff 100644 --- a/lib/pages/gallery/view/translator_dialog.dart +++ b/lib/pages/gallery/view/translator_dialog.dart @@ -1,5 +1,6 @@ import 'package:fehviewer/const/theme_colors.dart'; import 'package:fehviewer/utils/logger.dart'; +import 'package:fehviewer/utils/openl/translator_helper.dart'; import 'package:fehviewer/utils/vibrate.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -36,13 +37,22 @@ class TranslatorDialogView extends StatefulWidget { class _TranslatorDialogViewState extends State { final GoogleTranslator _translator = GoogleTranslator(); - late Future _future; + late Future _future; - Future _getTrans() async { + Future _getTrans() async { try { final Translation _trans = await _translator.translate(widget.inputText, to: 'zh-cn'); - return _trans; + return _trans.text; + } catch (e, stack) { + logger.e('$e\n$stack'); + return null; + } + } + + Future _getTransOpenL() async { + try { + return await TranslatorHelper.translateText(widget.inputText, to: 'zh'); } catch (e, stack) { logger.e('$e\n$stack'); return null; @@ -52,12 +62,13 @@ class _TranslatorDialogViewState extends State { @override void initState() { super.initState(); - _future = _getTrans(); + // _future = _getTrans(); + _future = _getTransOpenL(); } @override Widget build(BuildContext context) { - return FutureBuilder( + return FutureBuilder( future: _future, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { @@ -81,7 +92,7 @@ class _TranslatorDialogViewState extends State { child: Container( width: double.infinity, child: Text( - _trans?.text ?? '', + _trans ?? '', textAlign: TextAlign.start, style: TextStyle( height: 1.5, diff --git a/lib/utils/openl/language.dart b/lib/utils/openl/language.dart new file mode 100644 index 000000000..7ea2b2cf9 --- /dev/null +++ b/lib/utils/openl/language.dart @@ -0,0 +1,56 @@ +/// Language object with name and code (ISO) +class Language { + Language(this.code, this.name); + final String name; + final String code; + + @override + String toString() => name; +} + +/// Language list containing all languages supported by openl Translate API +class LanguageList { + static final Map _langs = { + 'auto': 'Automatic', + 'zh': 'Chinese', + 'en': 'English', + 'de': 'German', + 'fr': 'French', + 'it': 'Italian', + 'ja': 'Japanese', + 'es': 'Spanish', + 'nl': 'Dutch', + 'pl': 'Polish', + 'pt': 'Portuguese', + 'ru': 'Russian', + }; + + Language operator [](String code) { + code = code.toLowerCase(); + if (_langs.containsKey(code)) { + return Language(code, _langs[code]!); + } + throw LanguageNotSupportedException('$code is not a supported language.'); + } + + static bool contains(String codeOrLang) { + if (_langs.containsKey(codeOrLang) || + _langs.containsValue(codeOrLang.toCamelCase())) { + return true; + } + return false; + } +} + +class LanguageNotSupportedException implements Exception { + LanguageNotSupportedException(String lang) + : msg = '$lang is not a supported language.'; + + final String msg; +} + +extension _CamelCase on String { + String toCamelCase() { + return '${this[0].toUpperCase()}${substring(1).toLowerCase()}'; + } +} diff --git a/lib/utils/openl/openl_translator.dart b/lib/utils/openl/openl_translator.dart new file mode 100644 index 000000000..58e3308b4 --- /dev/null +++ b/lib/utils/openl/openl_translator.dart @@ -0,0 +1,50 @@ +import 'dart:convert' show jsonDecode, jsonEncode; + +import 'package:fehviewer/models/base/eh_models.dart'; +import 'package:fehviewer/utils/openl/language.dart'; + +import 'package:http/http.dart' as http; + +const String _baseUrl = 'api.openl.club'; + +class OpenLTranslator { + OpenLTranslator({required this.apikey}); + + final String apikey; + + Future translate( + String sourceText, { + String from = 'auto', + String to = 'en', + String service = 'deepl', + }) async { + for (final String each in [from, to]) { + if (!LanguageList.contains(each)) { + throw LanguageNotSupportedException(each); + } + } + + final String _path = '/services/$service/translate'; + + final Map reqMap = { + 'apikey': apikey, + 'text': sourceText, + 'source_lang': from, + 'target_lang': to, + }; + + final Uri url = Uri.https(_baseUrl, _path); + final data = await http.post(url, body: jsonEncode(reqMap)); + + if (data.statusCode != 200) { + throw http.ClientException('Error ${data.statusCode}: ${data.body}', url); + } + + final jsonData = jsonDecode(data.body); + if (jsonData == null) { + throw http.ClientException('Error: Can\'t parse json data'); + } + + return OpenlTranslation.fromJson(jsonData); + } +} diff --git a/lib/utils/openl/translator_helper.dart b/lib/utils/openl/translator_helper.dart new file mode 100644 index 000000000..2b86c77df --- /dev/null +++ b/lib/utils/openl/translator_helper.dart @@ -0,0 +1,43 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:fehviewer/models/openl_translation.dart'; +import 'package:fehviewer/utils/logger.dart'; +import 'package:fehviewer/utils/openl/openl_translator.dart'; +import 'package:flutter/services.dart'; + +class TranslatorHelper { + static Future getApikey() async { + final String openl = await rootBundle.loadString('assets/openl.json'); + final openlJson = json.decode(openl); + return openlJson['apikey'] ?? ''; + } + + static Future translate( + String sourceText, { + String from = 'auto', + String to = 'en', + String service = 'deepl', + }) async { + final String apikey = await getApikey(); + + logger.v('apikey $apikey'); + + final OpenLTranslator openLTranslator = OpenLTranslator(apikey: apikey); + return openLTranslator.translate(sourceText, from: from, to: to); + } + + static Future translateText( + String sourceText, { + String from = 'auto', + String to = 'en', + String service = 'deepl', + }) async { + final OpenlTranslation rult = + await translate(sourceText, from: from, to: to); + + logger.v(rult.toJson()); + + return rult.result ?? ''; + } +} diff --git a/pubspec.lock b/pubspec.lock index e42ca6450..d10f5f6d1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -14,7 +14,7 @@ packages: name: analyzer url: "https://pub.flutter-io.cn" source: hosted - version: "1.6.0" + version: "1.7.1" apn_json2model: dependency: "direct dev" description: @@ -63,7 +63,7 @@ packages: name: build url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.1" + version: "2.0.2" build_config: dependency: transitive description: @@ -84,7 +84,7 @@ packages: name: build_resolvers url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.2" + version: "2.0.3" build_runner: dependency: "direct dev" description: @@ -259,7 +259,7 @@ packages: name: device_info url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.1" + version: "2.0.2" device_info_platform_interface: dependency: transitive description: @@ -338,7 +338,7 @@ packages: name: ffi url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.0" + version: "1.1.1" file: dependency: transitive description: @@ -709,7 +709,7 @@ packages: name: json_serializable url: "https://pub.flutter-io.cn" source: hosted - version: "4.1.2" + version: "4.1.3" line_icons: dependency: "direct main" description: @@ -737,7 +737,7 @@ packages: name: local_auth url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.5" + version: "1.1.6" logger: dependency: "direct main" description: @@ -828,7 +828,7 @@ packages: name: package_info url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.1" + version: "2.0.2" path: dependency: transitive description: @@ -1017,7 +1017,7 @@ packages: name: share url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.2" + version: "2.0.4" shared_preferences: dependency: "direct main" description: @@ -1085,7 +1085,7 @@ packages: name: source_gen url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.0" + version: "1.0.1" source_span: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 7ba043e13..b545fd70b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: .. publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 1.1.13+178 +version: 1.1.14+179 environment: sdk: '>=2.12.0-0 <3.0.0' @@ -199,3 +199,6 @@ flutter: # - family: SourceHanSansSC # fonts: # - asset: fonts/SourceHanSansSC-Regular.otf + + assets: + - assets/openl.json \ No newline at end of file