因為目前的字典是寫死的,但追星時會有不同團體不同專有名詞、成員暱稱與流行語,想做個讓使用者可以自己新增「團體名、成員暱稱、粉絲名」的地方,讓翻譯起來可以更順暢
在 lib/features/live_translate/data/models/ 建立 fandom_word.dart
class FandomWord {
final String id;
final String original; // 原詞
final String translated; // 中文翻譯/中文暱稱
final String category; // 分類(如:成員暱稱, 團體名, 飯圈梗)
FandomWord({
required this.id,
required this.original,
required this.translated,
this.category = '成員暱稱',
});
Map<String, dynamic> toJson() => {
'id': id,
'original': original,
'translated': translated,
'category': category,
};
factory FandomWord.fromJson(Map<String, dynamic> json) => FandomWord(
id: json['id'],
original: json['original'],
translated: json['translated'],
category: json['category'] ?? '成員暱稱',
);
}
在 lib/features/live_translate/data/services/ 建立 dictionary_service.dart
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
import '../models/fandom_word.dart';
class DictionaryService {
static const String _key = 'user_fandom_dictionary';
/// 取得所有自訂單字
Future<List<FandomWord>> getWords() async {
final prefs = await SharedPreferences.getInstance();
final String? data = prefs.getString(_key);
if (data == null || data.isEmpty) return _getDefaultInitialWords();
final List<dynamic> jsonList = jsonDecode(data);
return jsonList.map((e) => FandomWord.fromJson(e)).toList();
}
/// 新增單字
Future<void> addWord(FandomWord word) async {
final words = await getWords();
words.add(word);
await _saveWords(words);
}
/// 刪除單字
Future<void> deleteWord(String id) async {
final words = await getWords();
words.removeWhere((item) => item.id == id);
await _saveWords(words);
}
Future<void> _saveWords(List<FandomWord> words) async {
final prefs = await SharedPreferences.getInstance();
final String jsonString = jsonEncode(words.map((e) => e.toJson()).toList());
await prefs.setString(_key, jsonString);
}
/// 預設基礎詞條
List<FandomWord> _getDefaultInitialWords() {
return [
FandomWord(id: '1', original: '김지원', translated: '金志垣', category: '成員暱稱'),
FandomWord(id: '2', original: '얼죽아', translated: '凍死也要喝冰美式', category: '飯圈梗'),
];
}
}
在 lib/features/live_translate/presentation/pages/ 建立 fandom_dictionary_page.dart
import 'package:flutter/material.dart';
import '../../data/models/fandom_word.dart';
import '../../data/services/dictionary_service.dart';
class FandomDictionaryPage extends StatefulWidget {
const FandomDictionaryPage({Key? key}) : super(key: key);
@override
State<FandomDictionaryPage> createState() => _FandomDictionaryPageState();
}
class _FandomDictionaryPageState extends State<FandomDictionaryPage> {
final DictionaryService _service = DictionaryService();
List<FandomWord> _words = [];
@override
void initState() {
super.initState();
_loadDictionary();
}
Future<void> _loadDictionary() async {
final list = await _service.getWords();
setState(() => _words = list);
}
void _showAddDialog() {
final origCtrl = TextEditingController();
final transCtrl = TextEditingController();
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('新增自訂專有名詞'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(controller: origCtrl, decoration: const InputDecoration(labelText: '原詞 (韓/日文)')),
TextField(controller: transCtrl, decoration: const InputDecoration(labelText: '對應譯名/暱稱')),
],
),
actions: [
TextButton(onPressed: () => Navigator.pop(ctx), child: const Text('取消')),
ElevatedButton(
onPressed: () async {
if (origCtrl.text.isNotEmpty && transCtrl.text.isNotEmpty) {
await _service.addWord(FandomWord(
id: DateTime.now().millisecondsSinceEpoch.toString(),
original: origCtrl.text.trim(),
translated: transCtrl.text.trim(),
));
Navigator.pop(ctx);
_loadDictionary();
}
},
child: const Text('新增'),
),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('自訂偶像專屬字典')),
body: ListView.builder(
itemCount: _words.length,
itemBuilder: (ctx, i) {
final word = _words[i];
return ListTile(
title: Text('${word.original} ➔ ${word.translated}'),
subtitle: Text(word.category),
trailing: IconButton(
icon: const Icon(Icons.delete_outline, color: Colors.redAccent),
onPressed: () async {
await _service.deleteWord(word.id);
_loadDictionary();
},
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: _showAddDialog,
child: const Icon(Icons.add),
),
);
}
}