libretranslatr
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import '../models/language.dart';
|
||||
import 'settings_service.dart';
|
||||
|
||||
class TranslateException implements Exception {
|
||||
final String message;
|
||||
TranslateException(this.message);
|
||||
@override
|
||||
String toString() => message;
|
||||
}
|
||||
|
||||
class DetectResult {
|
||||
final String language;
|
||||
final int confidence;
|
||||
DetectResult({required this.language, required this.confidence});
|
||||
}
|
||||
|
||||
/// Kullanıcının kendi sunucusundaki LibreTranslate API'sine istek atar.
|
||||
class TranslateService {
|
||||
final SettingsService _settings;
|
||||
TranslateService(this._settings);
|
||||
|
||||
Future<String> _baseUrl() async {
|
||||
final url = await _settings.getServerUrl();
|
||||
if (url == null || url.isEmpty) {
|
||||
throw TranslateException('Sunucu adresi ayarlanmamış. Ayarlar\'dan ekleyin.');
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
Map<String, dynamic> _withApiKey(Map<String, dynamic> body, String? apiKey) {
|
||||
if (apiKey != null && apiKey.isNotEmpty) {
|
||||
body['api_key'] = apiKey;
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
String _errorFromBody(String body, int statusCode) {
|
||||
try {
|
||||
final decoded = jsonDecode(body);
|
||||
if (decoded is Map && decoded['error'] != null) {
|
||||
return decoded['error'].toString();
|
||||
}
|
||||
} catch (_) {
|
||||
// JSON değilse aşağıda genel mesaj kullanılır.
|
||||
}
|
||||
return 'Sunucu hatası (HTTP $statusCode)';
|
||||
}
|
||||
|
||||
/// Sunucuya bağlanıp desteklenen dilleri getirir.
|
||||
/// Hem "bağlantı testi" hem de dil listesini doldurmak için kullanılır.
|
||||
Future<List<Language>> fetchLanguages() async {
|
||||
final base = await _baseUrl();
|
||||
final apiKey = await _settings.getApiKey();
|
||||
final uri = Uri.parse('$base/languages').replace(
|
||||
queryParameters: apiKey != null ? {'api_key': apiKey} : null,
|
||||
);
|
||||
|
||||
final res = await http.get(uri).timeout(const Duration(seconds: 10));
|
||||
if (res.statusCode != 200) {
|
||||
throw TranslateException(_errorFromBody(res.body, res.statusCode));
|
||||
}
|
||||
final List<dynamic> data = jsonDecode(utf8.decode(res.bodyBytes));
|
||||
return data.map((e) => Language.fromJson(e as Map<String, dynamic>)).toList();
|
||||
}
|
||||
|
||||
Future<String> translate({
|
||||
required String text,
|
||||
required String sourceLang,
|
||||
required String targetLang,
|
||||
}) async {
|
||||
if (text.trim().isEmpty) return '';
|
||||
final base = await _baseUrl();
|
||||
final apiKey = await _settings.getApiKey();
|
||||
|
||||
final body = _withApiKey({
|
||||
'q': text,
|
||||
'source': sourceLang,
|
||||
'target': targetLang,
|
||||
'format': 'text',
|
||||
}, apiKey);
|
||||
|
||||
final res = await http
|
||||
.post(
|
||||
Uri.parse('$base/translate'),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonEncode(body),
|
||||
)
|
||||
.timeout(const Duration(seconds: 15));
|
||||
|
||||
if (res.statusCode != 200) {
|
||||
throw TranslateException(_errorFromBody(res.body, res.statusCode));
|
||||
}
|
||||
final decoded = jsonDecode(utf8.decode(res.bodyBytes));
|
||||
return decoded['translatedText'] as String;
|
||||
}
|
||||
|
||||
Future<DetectResult?> detect(String text) async {
|
||||
if (text.trim().isEmpty) return null;
|
||||
final base = await _baseUrl();
|
||||
final apiKey = await _settings.getApiKey();
|
||||
|
||||
final body = _withApiKey({'q': text}, apiKey);
|
||||
|
||||
final res = await http
|
||||
.post(
|
||||
Uri.parse('$base/detect'),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonEncode(body),
|
||||
)
|
||||
.timeout(const Duration(seconds: 10));
|
||||
|
||||
if (res.statusCode != 200) {
|
||||
throw TranslateException(_errorFromBody(res.body, res.statusCode));
|
||||
}
|
||||
final List<dynamic> data = jsonDecode(utf8.decode(res.bodyBytes));
|
||||
if (data.isEmpty) return null;
|
||||
final best = data.first as Map<String, dynamic>;
|
||||
return DetectResult(
|
||||
language: best['language'] as String,
|
||||
confidence: ((best['confidence'] ?? 0) as num).round(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user