Flutter
Flutter에서 번역 기능 구현하기
GODOLs
2025. 1. 24. 14:11
Flutter에서 번역 기능 구현하기
1. 필요한 패키지 설치
먼저 pubspec.yaml에 필요한 패키지들을 추가합니다:
dependencies:
translator: ^1.0.3 # Google Translate API 사용
language\_detector: ^1.0.1 # 언어 감지
freezed\_annotation: 2.4.4 # 상태 관리를 위한 freezed
dev\_dependencies:
build\_runner: ^2.4.12
freezed: 2.4.4
2. TranslatorService 구현
번역 기능을 담당할 서비스 클래스를 만듭니다:
import 'package:language\_detector/language\_detector.dart';
import 'package:translator/translator.dart';
import 'package:riverpod\_annotation/riverpod\_annotation.dart';
@Riverpod(keepAlive: true)
class TranslatorService extends \_$TranslatorService {
@override
String? build() => null;
Future<String\> translate(String text) async {
final translator = GoogleTranslator();
final isSameLanguage = await detectSameLanguage(text);
// 같은 언어면 번역하지 않음
if (isSameLanguage) {
return text;
}
// 사용자가 선택한 언어로 번역
final translation = await translator.translate(text, to: 'ko');
return translation.text;
}
Future<bool\> detectSameLanguage(String text) async {
final languageCode = await LanguageDetector.getLanguageCode(content: text);
return languageCode == 'ko'; // 한국어인 경우
}
}
3. 상태 관리를 위한 Freezed 모델
게시글의 상태를 관리하기 위한 모델을 정의합니다:
@freezed
class Post with \_$Post {
const factory Post({
required String title,
required String titleTranslated,
required String content,
required String contentTranslated,
required bool isSameLanguage,
required bool isTranslated,
}) = \_Post;
}
4. 번역 기능 구현
class PostController extends \_$PostController {
Future<void\> changePostLanguage(String postId) async {
final post = state.value!.posts.firstWhere((post) => post.id == postId);
// 이미 같은 언어면 번역하지 않음
if (post.isSameLanguage) return;
// 번역된 내용이 있으면 캐시된 내용 사용
if (post.isTranslated) {
final translatedPost = post.copyWith(
titleTranslated: post.titleTranslated,
contentTranslated: post.contentTranslated,
isTranslated: true,
);
\_updatePost(postId, translatedPost);
return;
}
// 새로운 번역 수행
final translatedTitle = await \_translatorService.translate(post.title);
final translatedContent = await \_translatorService.translate(post.content);
final translatedPost = post.copyWith(
titleTranslated: translatedTitle,
contentTranslated: translatedContent,
isTranslated: true,
);
\_updatePost(postId, translatedPost);
}
// 원본으로 복원
Future<void\> restorePostLanguage(String postId) async {
final post = state.value!.posts.firstWhere((post) => post.id == postId);
final restoredPost = post.copyWith(
titleTranslated: post.title,
contentTranslated: post.content,
isTranslated: false,
);
\_updatePost(postId, restoredPost);
}
}
5. UI 구현
class TranslatePostCard extends ConsumerWidget {
final Post post;
const TranslatePostCard({
Key? key,
required this.post,
}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return Card(
margin: const EdgeInsets.all(16.0),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: \[
// 제목
Text(
post.isTranslated ? post.titleTranslated : post.title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
// 본문
Text(
post.isTranslated ? post.contentTranslated : post.content,
style: const TextStyle(fontSize: 16),
),
const SizedBox(height: 16),
// 번역 버튼
if (!post.isSameLanguage) // 같은 언어가 아닐 때만 번역 버튼 표시
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: \[
TranslateButton(
isTranslated: post.isTranslated,
onPressed: () {
if (post.isTranslated) {
ref.read(postControllerProvider.notifier)
.restorePostLanguage(post.id);
} else {
ref.read(postControllerProvider.notifier)
.changePostLanguage(post.id);
}
},
),
\],
),
\],
),
),
);
}
}
// 번역 버튼 위젯
class TranslateButton extends StatelessWidget {
final bool isTranslated;
final VoidCallback onPressed;
const TranslateButton({
Key? key,
required this.isTranslated,
required this.onPressed,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return TextButton.icon(
onPressed: onPressed,
icon: Icon(
isTranslated ? Icons.language : Icons.translate,
size: 20,
color: Colors.blue,
),
label: Text(
isTranslated ? '원본 보기' : '번역하기',
style: const TextStyle(
color: Colors.blue,
fontSize: 14,
),
),
);
}
}
6. 원본 유지의 장점
- 성능 최적화:
- 한번 번역된 내용을 캐시로 저장해두면 반복적인 API 호출을 줄일 수 있습니다.
- 사용자가 원본과 번역본을 전환할 때 즉각적인 응답이 가능합니다.
- 사용자 경험:
- 원본과 번역본을 빠르게 전환할 수 있어 더 나은 UX를 제공합니다.
- 번역의 정확도를 사용자가 직접 확인할 수 있습니다.
- 데이터 무결성:
- 원본 데이터가 보존되어 있어 번역 오류가 발생하더라도 복구가 가능합니다.
- 중요한 정보가 번역 과정에서 손실되는 것을 방지합니다.
- 비용 절감:
- 불필요한 번역 API 호출을 줄여 비용을 절감할 수 있습니다.
- 캐시된 번역 결과를 재사용하여 서버 부하를 줄일 수 있습니다.
마무리
이렇게 구현된 번역 기능은 사용자들에게 다음과 같은 이점을 제공합니다:
- 직관적인 UI로 쉽게 번역 기능을 사용할 수 있습니다.
- 원본과 번역본을 자유롭게 전환할 수 있습니다.
- 빠른 응답 속도로 좋은 사용자 경험을 제공합니다.
- 효율적인 리소스 관리로 안정적인 서비스가 가능합니다.
Freezed를 활용한 상태 관리와 원본 데이터 보존 전략으로 안정적이고 효율적인 번역 기능을 구현할 수 있습니다.
반응형