feat: 다국어 지원 및 다중 통화 환율 변환 기능 확대
- ExchangeRateService에 JPY, CNY 환율 지원 추가 - 구독 서비스별 다국어 표시 이름 지원 - 분석 화면 차트 및 UI/UX 개선 - 설정 화면 전면 리팩토링 - SMS 스캔 기능 사용성 개선 - 전체 앱 다국어 번역 확대 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class AppLocalizations {
|
||||
final Locale locale;
|
||||
late Map<String, dynamic> _localizedStrings;
|
||||
|
||||
AppLocalizations(this.locale);
|
||||
|
||||
@@ -9,126 +12,467 @@ class AppLocalizations {
|
||||
return Localizations.of<AppLocalizations>(context, AppLocalizations)!;
|
||||
}
|
||||
|
||||
static const _localizedValues = <String, Map<String, String>>{
|
||||
'en': {
|
||||
'appTitle': 'SubManager',
|
||||
'subscriptionManagement': 'Subscription Management',
|
||||
'addSubscription': 'Add Subscription',
|
||||
'subscriptionName': 'Service Name',
|
||||
'monthlyCost': 'Monthly Cost',
|
||||
'billingCycle': 'Billing Cycle',
|
||||
'nextBillingDate': 'Next Billing Date',
|
||||
'save': 'Save',
|
||||
'cancel': 'Cancel',
|
||||
'delete': 'Delete',
|
||||
'edit': 'Edit',
|
||||
'totalSubscriptions': 'Total Subscriptions',
|
||||
'totalMonthlyExpense': 'Total Monthly Expense',
|
||||
'noSubscriptions': 'No subscriptions registered',
|
||||
'addSubscriptionNow': 'Add Subscription Now',
|
||||
'paymentReminder': 'Payment Reminder',
|
||||
'expirationReminder': 'Expiration Reminder',
|
||||
'daysLeft': 'days left',
|
||||
'categoryManagement': 'Category Management',
|
||||
'categoryName': 'Category Name',
|
||||
'selectColor': 'Select Color',
|
||||
'selectIcon': 'Select Icon',
|
||||
'addCategory': 'Add Category',
|
||||
'settings': 'Settings',
|
||||
'darkMode': 'Dark Mode',
|
||||
'language': 'Language',
|
||||
'notifications': 'Notifications',
|
||||
'appLock': 'App Lock',
|
||||
},
|
||||
'ko': {
|
||||
'appTitle': '구독 관리',
|
||||
'subscriptionManagement': '구독 관리',
|
||||
'addSubscription': '구독 추가',
|
||||
'subscriptionName': '서비스명',
|
||||
'monthlyCost': '월 비용',
|
||||
'billingCycle': '결제 주기',
|
||||
'nextBillingDate': '다음 결제일',
|
||||
'save': '저장',
|
||||
'cancel': '취소',
|
||||
'delete': '삭제',
|
||||
'edit': '수정',
|
||||
'totalSubscriptions': '총 구독',
|
||||
'totalMonthlyExpense': '이번 달 총 지출',
|
||||
'noSubscriptions': '등록된 구독 서비스가 없습니다',
|
||||
'addSubscriptionNow': '구독 추가하기',
|
||||
'paymentReminder': '결제 예정 알림',
|
||||
'expirationReminder': '만료 예정 알림',
|
||||
'daysLeft': '일 남음',
|
||||
'categoryManagement': '카테고리 관리',
|
||||
'categoryName': '카테고리 이름',
|
||||
'selectColor': '색상 선택',
|
||||
'selectIcon': '아이콘 선택',
|
||||
'addCategory': '카테고리 추가',
|
||||
'settings': '설정',
|
||||
'darkMode': '다크 모드',
|
||||
'language': '언어',
|
||||
'notifications': '알림',
|
||||
'appLock': '앱 잠금',
|
||||
},
|
||||
};
|
||||
// JSON 파일에서 번역 데이터 로드
|
||||
Future<void> load() async {
|
||||
String jsonString =
|
||||
await rootBundle.loadString('assets/data/text.json');
|
||||
Map<String, dynamic> jsonMap = json.decode(jsonString);
|
||||
_localizedStrings = jsonMap[locale.languageCode];
|
||||
}
|
||||
|
||||
String get appTitle => _localizedValues[locale.languageCode]!['appTitle']!;
|
||||
String get appTitle => _localizedStrings['appTitle'] ?? 'SubManager';
|
||||
String get appSubtitle => _localizedStrings['appSubtitle'] ?? 'Manage subscriptions easily';
|
||||
String get subscriptionManagement =>
|
||||
_localizedValues[locale.languageCode]!['subscriptionManagement']!;
|
||||
_localizedStrings['subscriptionManagement'] ?? 'Subscription Management';
|
||||
String get addSubscription =>
|
||||
_localizedValues[locale.languageCode]!['addSubscription']!;
|
||||
_localizedStrings['addSubscription'] ?? 'Add Subscription';
|
||||
String get subscriptionName =>
|
||||
_localizedValues[locale.languageCode]!['subscriptionName']!;
|
||||
_localizedStrings['subscriptionName'] ?? 'Service Name';
|
||||
String get monthlyCost =>
|
||||
_localizedValues[locale.languageCode]!['monthlyCost']!;
|
||||
_localizedStrings['monthlyCost'] ?? 'Monthly Cost';
|
||||
String get billingCycle =>
|
||||
_localizedValues[locale.languageCode]!['billingCycle']!;
|
||||
_localizedStrings['billingCycle'] ?? 'Billing Cycle';
|
||||
String get nextBillingDate =>
|
||||
_localizedValues[locale.languageCode]!['nextBillingDate']!;
|
||||
String get save => _localizedValues[locale.languageCode]!['save']!;
|
||||
String get cancel => _localizedValues[locale.languageCode]!['cancel']!;
|
||||
String get delete => _localizedValues[locale.languageCode]!['delete']!;
|
||||
String get edit => _localizedValues[locale.languageCode]!['edit']!;
|
||||
_localizedStrings['nextBillingDate'] ?? 'Next Billing Date';
|
||||
String get save => _localizedStrings['save'] ?? 'Save';
|
||||
String get cancel => _localizedStrings['cancel'] ?? 'Cancel';
|
||||
String get delete => _localizedStrings['delete'] ?? 'Delete';
|
||||
String get edit => _localizedStrings['edit'] ?? 'Edit';
|
||||
String get totalSubscriptions =>
|
||||
_localizedValues[locale.languageCode]!['totalSubscriptions']!;
|
||||
_localizedStrings['totalSubscriptions'] ?? 'Total Subscriptions';
|
||||
String get totalMonthlyExpense =>
|
||||
_localizedValues[locale.languageCode]!['totalMonthlyExpense']!;
|
||||
_localizedStrings['totalMonthlyExpense'] ?? 'Total Monthly Expense';
|
||||
String get noSubscriptions =>
|
||||
_localizedValues[locale.languageCode]!['noSubscriptions']!;
|
||||
_localizedStrings['noSubscriptions'] ?? 'No subscriptions registered';
|
||||
String get addSubscriptionNow =>
|
||||
_localizedValues[locale.languageCode]!['addSubscriptionNow']!;
|
||||
_localizedStrings['addSubscriptionNow'] ?? 'Add Subscription Now';
|
||||
String get paymentReminder =>
|
||||
_localizedValues[locale.languageCode]!['paymentReminder']!;
|
||||
_localizedStrings['paymentReminder'] ?? 'Payment Reminder';
|
||||
String get expirationReminder =>
|
||||
_localizedValues[locale.languageCode]!['expirationReminder']!;
|
||||
String get daysLeft => _localizedValues[locale.languageCode]!['daysLeft']!;
|
||||
_localizedStrings['expirationReminder'] ?? 'Expiration Reminder';
|
||||
String get daysLeft => _localizedStrings['daysLeft'] ?? 'days left';
|
||||
String get categoryManagement =>
|
||||
_localizedValues[locale.languageCode]!['categoryManagement']!;
|
||||
_localizedStrings['categoryManagement'] ?? 'Category Management';
|
||||
String get categoryName =>
|
||||
_localizedValues[locale.languageCode]!['categoryName']!;
|
||||
_localizedStrings['categoryName'] ?? 'Category Name';
|
||||
String get selectColor =>
|
||||
_localizedValues[locale.languageCode]!['selectColor']!;
|
||||
_localizedStrings['selectColor'] ?? 'Select Color';
|
||||
String get selectIcon =>
|
||||
_localizedValues[locale.languageCode]!['selectIcon']!;
|
||||
_localizedStrings['selectIcon'] ?? 'Select Icon';
|
||||
String get addCategory =>
|
||||
_localizedValues[locale.languageCode]!['addCategory']!;
|
||||
String get settings => _localizedValues[locale.languageCode]!['settings']!;
|
||||
String get darkMode => _localizedValues[locale.languageCode]!['darkMode']!;
|
||||
String get language => _localizedValues[locale.languageCode]!['language']!;
|
||||
_localizedStrings['addCategory'] ?? 'Add Category';
|
||||
String get settings => _localizedStrings['settings'] ?? 'Settings';
|
||||
String get darkMode => _localizedStrings['darkMode'] ?? 'Dark Mode';
|
||||
String get language => _localizedStrings['language'] ?? 'Language';
|
||||
String get notifications =>
|
||||
_localizedValues[locale.languageCode]!['notifications']!;
|
||||
String get appLock => _localizedValues[locale.languageCode]!['appLock']!;
|
||||
_localizedStrings['notifications'] ?? 'Notifications';
|
||||
String get appLock => _localizedStrings['appLock'] ?? 'App Lock';
|
||||
// 알림 설정
|
||||
String get notificationPermission =>
|
||||
_localizedStrings['notificationPermission'] ?? 'Notification Permission';
|
||||
String get notificationPermissionDesc =>
|
||||
_localizedStrings['notificationPermissionDesc'] ?? 'Permission is required to receive notifications';
|
||||
String get requestPermission =>
|
||||
_localizedStrings['requestPermission'] ?? 'Request Permission';
|
||||
String get paymentNotification =>
|
||||
_localizedStrings['paymentNotification'] ?? 'Payment Due Notification';
|
||||
String get paymentNotificationDesc =>
|
||||
_localizedStrings['paymentNotificationDesc'] ?? 'Receive notification on payment due date';
|
||||
String get notificationTiming =>
|
||||
_localizedStrings['notificationTiming'] ?? 'Notification Timing';
|
||||
String get notificationTime =>
|
||||
_localizedStrings['notificationTime'] ?? 'Notification Time';
|
||||
String get dailyReminder =>
|
||||
_localizedStrings['dailyReminder'] ?? 'Daily Reminder';
|
||||
String get dailyReminderEnabled =>
|
||||
_localizedStrings['dailyReminderEnabled'] ?? 'Receive daily notifications until payment date';
|
||||
String get dailyReminderDisabled =>
|
||||
_localizedStrings['dailyReminderDisabled'] ?? 'Receive notification @ day(s) before payment';
|
||||
String get notificationPermissionDenied =>
|
||||
_localizedStrings['notificationPermissionDenied'] ?? 'Notification permission denied';
|
||||
// 앱 정보
|
||||
String get appInfo => _localizedStrings['appInfo'] ?? 'App Info';
|
||||
String get version => _localizedStrings['version'] ?? 'Version';
|
||||
String get appDescription =>
|
||||
_localizedStrings['appDescription'] ?? 'Subscription Management App';
|
||||
String get developer => _localizedStrings['developer'] ?? 'Developer';
|
||||
String get cannotOpenStore =>
|
||||
_localizedStrings['cannotOpenStore'] ?? 'Cannot open store';
|
||||
// 테마
|
||||
String get lightTheme => _localizedStrings['lightTheme'] ?? 'Light';
|
||||
String get darkTheme => _localizedStrings['darkTheme'] ?? 'Dark';
|
||||
String get oledTheme => _localizedStrings['oledTheme'] ?? 'OLED Black';
|
||||
String get systemTheme => _localizedStrings['systemTheme'] ?? 'System Default';
|
||||
// 기타 메시지
|
||||
String get subscriptionAdded =>
|
||||
_localizedStrings['subscriptionAdded'] ?? 'Subscription added';
|
||||
// 언어 설정
|
||||
String get korean => _localizedStrings['korean'] ?? '한국어';
|
||||
String get english => _localizedStrings['english'] ?? 'English';
|
||||
String get japanese => _localizedStrings['japanese'] ?? '日本語';
|
||||
String get chinese => _localizedStrings['chinese'] ?? '中文';
|
||||
// 날짜
|
||||
String get oneDayBefore => _localizedStrings['oneDayBefore'] ?? '1 day before';
|
||||
String get twoDaysBefore => _localizedStrings['twoDaysBefore'] ?? '2 days before';
|
||||
String get threeDaysBefore => _localizedStrings['threeDaysBefore'] ?? '3 days before';
|
||||
// 추가 메시지
|
||||
String get requiredFieldsError => _localizedStrings['requiredFieldsError'] ?? 'Please fill in all required fields';
|
||||
String get subscriptionUpdated => _localizedStrings['subscriptionUpdated'] ?? 'Subscription information has been updated';
|
||||
String get officialCancelPageNotFound => _localizedStrings['officialCancelPageNotFound'] ?? 'Official cancellation page not found. Redirecting to Google search.';
|
||||
String get cannotOpenWebsite => _localizedStrings['cannotOpenWebsite'] ?? 'Cannot open website';
|
||||
String get noWebsiteInfo => _localizedStrings['noWebsiteInfo'] ?? 'No website information available. Please cancel through the website.';
|
||||
String get editMode => _localizedStrings['editMode'] ?? 'Edit Mode';
|
||||
String get changesAppliedAfterSave => _localizedStrings['changesAppliedAfterSave'] ?? 'Changes will be applied after saving';
|
||||
String get saveChanges => _localizedStrings['saveChanges'] ?? 'Save Changes';
|
||||
String get monthlyExpense => _localizedStrings['monthlyExpense'] ?? 'Monthly Expense';
|
||||
String get websiteUrl => _localizedStrings['websiteUrl'] ?? 'Website URL';
|
||||
String get websiteUrlOptional => _localizedStrings['websiteUrlOptional'] ?? 'Website URL (Optional)';
|
||||
String get eventPrice => _localizedStrings['eventPrice'] ?? 'Event Price';
|
||||
String get eventPriceHint => _localizedStrings['eventPriceHint'] ?? 'Enter discounted price';
|
||||
String get eventPriceRequired => _localizedStrings['eventPriceRequired'] ?? 'Please enter event price';
|
||||
String get invalidPrice => _localizedStrings['invalidPrice'] ?? 'Please enter a valid price';
|
||||
String get smsScanLabel => _localizedStrings['smsScanLabel'] ?? 'SMS';
|
||||
String get home => _localizedStrings['home'] ?? 'Home';
|
||||
String get analysis => _localizedStrings['analysis'] ?? 'Analysis';
|
||||
String get back => _localizedStrings['back'] ?? 'Back';
|
||||
String get exitApp => _localizedStrings['exitApp'] ?? 'Exit App';
|
||||
String get exitAppConfirm => _localizedStrings['exitAppConfirm'] ?? 'Are you sure you want to exit SubManager?';
|
||||
String get exit => _localizedStrings['exit'] ?? 'Exit';
|
||||
String get pageNotFound => _localizedStrings['pageNotFound'] ?? 'Page not found';
|
||||
String get serviceNameExample => _localizedStrings['serviceNameExample'] ?? 'e.g. Netflix, Spotify';
|
||||
String get urlExample => _localizedStrings['urlExample'] ?? 'https://example.com';
|
||||
String get appLockDesc => _localizedStrings['appLockDesc'] ?? 'App lock with biometric authentication';
|
||||
String get unlockWithBiometric => _localizedStrings['unlockWithBiometric'] ?? 'Unlock with biometric authentication';
|
||||
String get authenticationFailed => _localizedStrings['authenticationFailed'] ?? 'Authentication failed. Please try again.';
|
||||
String get smsPermissionRequired => _localizedStrings['smsPermissionRequired'] ?? 'SMS permission required';
|
||||
String get noSubscriptionSmsFound => _localizedStrings['noSubscriptionSmsFound'] ?? 'No subscription related SMS found';
|
||||
String get smsScanError => _localizedStrings['smsScanError'] ?? 'Error occurred during SMS scan';
|
||||
String get saveError => _localizedStrings['saveError'] ?? 'Error occurred while saving';
|
||||
String get newSubscriptionSmsNotFound => _localizedStrings['newSubscriptionSmsNotFound'] ?? 'No new subscription SMS found';
|
||||
String get subscriptionAddError => _localizedStrings['subscriptionAddError'] ?? 'Error adding subscription';
|
||||
String get allSubscriptionsProcessed => _localizedStrings['allSubscriptionsProcessed'] ?? 'All subscriptions have been processed.';
|
||||
String get websiteUrlExtracted => _localizedStrings['websiteUrlExtracted'] ?? 'Website URL (Auto-extracted)';
|
||||
String get startDate => _localizedStrings['startDate'] ?? 'Start Date';
|
||||
String get endDate => _localizedStrings['endDate'] ?? 'End Date';
|
||||
|
||||
// 새로 추가된 항목들
|
||||
String get monthlyTotalSubscriptionCost => _localizedStrings['monthlyTotalSubscriptionCost'] ?? 'Total Monthly Subscription Cost';
|
||||
String get todaysExchangeRate => _localizedStrings['todaysExchangeRate'] ?? 'Today\'s Exchange Rate';
|
||||
String get won => _localizedStrings['won'] ?? 'KRW';
|
||||
String get estimatedAnnualCost => _localizedStrings['estimatedAnnualCost'] ?? 'Estimated Annual Cost';
|
||||
String get totalSubscriptionServices => _localizedStrings['totalSubscriptionServices'] ?? 'Total Subscription Services';
|
||||
String get services => _localizedStrings['services'] ?? 'services';
|
||||
String get eventDiscountActive => _localizedStrings['eventDiscountActive'] ?? 'Event Discount Active';
|
||||
String get saving => _localizedStrings['saving'] ?? 'Saving';
|
||||
String get paymentDueToday => _localizedStrings['paymentDueToday'] ?? 'Payment Due Today';
|
||||
String get paymentInfoNeeded => _localizedStrings['paymentInfoNeeded'] ?? 'Payment Info Needed';
|
||||
String get event => _localizedStrings['event'] ?? 'Event';
|
||||
|
||||
// 카테고리 getter들
|
||||
String get categoryMusic => _localizedStrings['categoryMusic'] ?? 'Music';
|
||||
String get categoryOttVideo => _localizedStrings['categoryOttVideo'] ?? 'OTT(Video)';
|
||||
String get categoryStorageCloud => _localizedStrings['categoryStorageCloud'] ?? 'Storage/Cloud';
|
||||
String get categoryTelecomInternetTv => _localizedStrings['categoryTelecomInternetTv'] ?? 'Telecom · Internet · TV';
|
||||
String get categoryLifestyle => _localizedStrings['categoryLifestyle'] ?? 'Lifestyle';
|
||||
String get categoryShoppingEcommerce => _localizedStrings['categoryShoppingEcommerce'] ?? 'Shopping/E-commerce';
|
||||
String get categoryProgramming => _localizedStrings['categoryProgramming'] ?? 'Programming';
|
||||
String get categoryCollaborationOffice => _localizedStrings['categoryCollaborationOffice'] ?? 'Collaboration/Office';
|
||||
String get categoryAiService => _localizedStrings['categoryAiService'] ?? 'AI Service';
|
||||
String get categoryOther => _localizedStrings['categoryOther'] ?? 'Other';
|
||||
|
||||
// 동적 메시지 생성 메서드
|
||||
String daysBefore(int days) {
|
||||
return '$days${_localizedStrings['daysBefore'] ?? 'day(s) before'}';
|
||||
}
|
||||
|
||||
String dailyReminderDisabledWithDays(int days) {
|
||||
final template = _localizedStrings['dailyReminderDisabled'] ?? 'Receive notification @ day(s) before payment';
|
||||
return template.replaceAll('@', days.toString());
|
||||
}
|
||||
|
||||
String subscriptionAddedWithName(String serviceName) {
|
||||
final template = _localizedStrings['subscriptionAddedTemplate'] ?? '@ 구독이 추가되었습니다.';
|
||||
return template.replaceAll('@', serviceName);
|
||||
}
|
||||
|
||||
String subscriptionDeleted(String serviceName) {
|
||||
final template = _localizedStrings['subscriptionDeleted'] ?? '@ subscription has been deleted';
|
||||
return template.replaceAll('@', serviceName);
|
||||
}
|
||||
|
||||
String totalExpenseCopied(String amount) {
|
||||
final template = _localizedStrings['totalExpenseCopied'] ?? 'Total expense copied: @';
|
||||
return template.replaceAll('@', amount);
|
||||
}
|
||||
|
||||
String serviceRecognized(String serviceName) {
|
||||
final template = _localizedStrings['serviceRecognized'] ?? '@ service has been recognized automatically.';
|
||||
return template.replaceAll('@', serviceName);
|
||||
}
|
||||
|
||||
String smsScanErrorWithMessage(String error) {
|
||||
final template = _localizedStrings['smsScanError'] ?? 'Error occurred during SMS scan: @';
|
||||
return template.replaceAll('@', error);
|
||||
}
|
||||
|
||||
String saveErrorWithMessage(String error) {
|
||||
final template = _localizedStrings['saveError'] ?? 'Error occurred while saving: @';
|
||||
return template.replaceAll('@', error);
|
||||
}
|
||||
|
||||
String subscriptionAddErrorWithMessage(String error) {
|
||||
final template = _localizedStrings['subscriptionAddError'] ?? 'Error adding subscription: @';
|
||||
return template.replaceAll('@', error);
|
||||
}
|
||||
|
||||
String subscriptionSkipped(String serviceName) {
|
||||
final template = _localizedStrings['subscriptionSkipped'] ?? '@ subscription skipped.';
|
||||
return template.replaceAll('@', serviceName);
|
||||
}
|
||||
|
||||
// 홈화면 관련
|
||||
String get mySubscriptions => _localizedStrings['mySubscriptions'] ?? 'My Subscriptions';
|
||||
|
||||
String subscriptionCount(int count) {
|
||||
if (locale.languageCode == 'ko') {
|
||||
return '${count}개';
|
||||
} else if (locale.languageCode == 'ja') {
|
||||
return '${count}個';
|
||||
} else if (locale.languageCode == 'zh') {
|
||||
return '${count}个';
|
||||
} else {
|
||||
return count.toString();
|
||||
}
|
||||
}
|
||||
|
||||
// 분석화면 관련
|
||||
String get monthlyExpenseTitle => _localizedStrings['monthlyExpenseTitle'] ?? 'Monthly Expense Status';
|
||||
String get recentSixMonthsTrend => _localizedStrings['recentSixMonthsTrend'] ?? 'Recent 6 months trend';
|
||||
String get monthlySubscriptionExpense => _localizedStrings['monthlySubscriptionExpense'] ?? 'Monthly subscription expense';
|
||||
String get subscriptionServiceRatio => _localizedStrings['subscriptionServiceRatio'] ?? 'Subscription Service Ratio';
|
||||
String get monthlyExpenseBasis => _localizedStrings['monthlyExpenseBasis'] ?? 'Based on monthly expense';
|
||||
String get noSubscriptionServices => _localizedStrings['noSubscriptionServices'] ?? 'No subscription services';
|
||||
String get totalExpenseSummary => _localizedStrings['totalExpenseSummary'] ?? 'Total Expense Summary';
|
||||
String get monthlyTotalAmount => _localizedStrings['monthlyTotalAmount'] ?? 'Monthly Total Amount';
|
||||
String get totalExpense => _localizedStrings['totalExpense'] ?? 'Total Expense';
|
||||
String get totalServices => _localizedStrings['totalServices'] ?? 'Total Services';
|
||||
String get servicesUnit => _localizedStrings['servicesUnit'] ?? 'services';
|
||||
String get averageCost => _localizedStrings['averageCost'] ?? 'Average Cost';
|
||||
String get eventDiscountStatus => _localizedStrings['eventDiscountStatus'] ?? 'Event Discount Status';
|
||||
String get inProgressUnit => _localizedStrings['inProgressUnit'] ?? 'in progress';
|
||||
String get monthlySavingAmount => _localizedStrings['monthlySavingAmount'] ?? 'Monthly Saving Amount';
|
||||
String get eventsInProgress => _localizedStrings['eventsInProgress'] ?? 'Events in Progress';
|
||||
String get discountPercent => _localizedStrings['discountPercent'] ?? '% discount';
|
||||
String get currencyWon => _localizedStrings['currencyWon'] ?? 'KRW';
|
||||
|
||||
// SMS 스캔 관련
|
||||
String get scanningMessages => _localizedStrings['scanningMessages'] ?? 'Scanning SMS messages...';
|
||||
String get findingSubscriptions => _localizedStrings['findingSubscriptions'] ?? 'Finding subscription services';
|
||||
String get subscriptionNotFound => _localizedStrings['subscriptionNotFound'] ?? 'Subscription information not found.';
|
||||
String get repeatSubscriptionNotFound => _localizedStrings['repeatSubscriptionNotFound'] ?? 'No repeated subscription information found.';
|
||||
String get newSubscriptionNotFound => _localizedStrings['newSubscriptionNotFound'] ?? 'No new subscription SMS found';
|
||||
String get findRepeatSubscriptions => _localizedStrings['findRepeatSubscriptions'] ?? 'Find subscriptions paid 2+ times';
|
||||
String get scanTextMessages => _localizedStrings['scanTextMessages'] ?? 'Scan text messages to automatically find repeatedly paid subscriptions. Service names and amounts can be extracted for easy subscription addition.';
|
||||
String get startScanning => _localizedStrings['startScanning'] ?? 'Start Scanning';
|
||||
String get foundSubscription => _localizedStrings['foundSubscription'] ?? 'Found subscription';
|
||||
String get serviceName => _localizedStrings['serviceName'] ?? 'Service Name';
|
||||
String get nextBillingDateLabel => _localizedStrings['nextBillingDateLabel'] ?? 'Next Billing Date';
|
||||
String get category => _localizedStrings['category'] ?? 'Category';
|
||||
String get websiteUrlAuto => _localizedStrings['websiteUrlAuto'] ?? 'Website URL (Auto-extracted)';
|
||||
String get websiteUrlHint => _localizedStrings['websiteUrlHint'] ?? 'Edit website URL or leave empty';
|
||||
String get skip => _localizedStrings['skip'] ?? 'Skip';
|
||||
String get add => _localizedStrings['add'] ?? 'Add';
|
||||
String get nextBillingDateRequired => _localizedStrings['nextBillingDateRequired'] ?? 'Next billing date verification required';
|
||||
|
||||
String nextBillingDateEstimated(String date, int days) {
|
||||
final template = _localizedStrings['nextBillingDateEstimated'] ?? 'Next estimated billing date: @ (# days later)';
|
||||
return template.replaceAll('@', date).replaceAll('#', days.toString());
|
||||
}
|
||||
|
||||
String nextBillingDateInfo(String date, int days) {
|
||||
final template = _localizedStrings['nextBillingDateInfo'] ?? 'Next billing date: @ (# days later)';
|
||||
return template.replaceAll('@', date).replaceAll('#', days.toString());
|
||||
}
|
||||
|
||||
String get nextBillingDatePastRequired => _localizedStrings['nextBillingDatePastRequired'] ?? 'Next billing date verification required (past date)';
|
||||
|
||||
String formatDate(DateTime date) {
|
||||
if (locale.languageCode == 'ko') {
|
||||
return '${date.year}년 ${date.month}월 ${date.day}일';
|
||||
} else if (locale.languageCode == 'ja') {
|
||||
return '${date.year}年${date.month}月${date.day}日';
|
||||
} else if (locale.languageCode == 'zh') {
|
||||
return '${date.year}年${date.month}月${date.day}日';
|
||||
} else {
|
||||
final months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||||
return '${months[date.month - 1]} ${date.day}, ${date.year}';
|
||||
}
|
||||
}
|
||||
|
||||
String repeatCountDetected(int count) {
|
||||
final template = _localizedStrings['repeatCountDetected'] ?? '@ payment(s) detected';
|
||||
return template.replaceAll('@', count.toString());
|
||||
}
|
||||
|
||||
String servicesInProgress(int count) {
|
||||
if (locale.languageCode == 'ko') {
|
||||
return '${count}개 진행중';
|
||||
} else if (locale.languageCode == 'ja') {
|
||||
return '${count}個進行中';
|
||||
} else if (locale.languageCode == 'zh') {
|
||||
return '${count}个进行中';
|
||||
} else {
|
||||
return '$count in progress';
|
||||
}
|
||||
}
|
||||
|
||||
// 새로 추가된 동적 메서드들
|
||||
String paymentDueInDays(int days) {
|
||||
final template = _localizedStrings['paymentDueInDays'] ?? 'Payment due in @ days';
|
||||
return template.replaceAll('@', days.toString());
|
||||
}
|
||||
|
||||
String daysRemaining(int days) {
|
||||
final template = _localizedStrings['daysRemaining'] ?? '@ days remaining';
|
||||
return template.replaceAll('@', days.toString());
|
||||
}
|
||||
|
||||
String exchangeRateFormat(String rate) {
|
||||
final template = _localizedStrings['exchangeRateFormat'] ?? 'Today\'s rate: @';
|
||||
return template.replaceAll('@', rate);
|
||||
}
|
||||
|
||||
// 결제 주기 결제 메시지
|
||||
String get billingCyclePayment => _localizedStrings['billingCyclePayment'] ?? '@ Payment';
|
||||
|
||||
// 할인 금액 표시 getter들
|
||||
String get discountAmountWon => _localizedStrings['discountAmountWon'] ?? 'Save ₩@';
|
||||
String get discountAmountDollar => _localizedStrings['discountAmountDollar'] ?? 'Save \$@';
|
||||
String get discountAmountYen => _localizedStrings['discountAmountYen'] ?? 'Save ¥@';
|
||||
String get discountAmountYuan => _localizedStrings['discountAmountYuan'] ?? 'Save ¥@';
|
||||
|
||||
// 결제 주기 관련 getter
|
||||
String get monthly => _localizedStrings['monthly'] ?? 'Monthly';
|
||||
String get weekly => _localizedStrings['weekly'] ?? 'Weekly';
|
||||
String get yearly => _localizedStrings['yearly'] ?? 'Yearly';
|
||||
String get billingCycleMonthly => _localizedStrings['billingCycleMonthly'] ?? 'Monthly';
|
||||
String get billingCycleQuarterly => _localizedStrings['billingCycleQuarterly'] ?? 'Quarterly';
|
||||
String get billingCycleHalfYearly => _localizedStrings['billingCycleHalfYearly'] ?? 'Half-Yearly';
|
||||
String get billingCycleYearly => _localizedStrings['billingCycleYearly'] ?? 'Yearly';
|
||||
|
||||
// 색상 관련 getter
|
||||
String get colorBlue => _localizedStrings['colorBlue'] ?? 'Blue';
|
||||
String get colorGreen => _localizedStrings['colorGreen'] ?? 'Green';
|
||||
String get colorOrange => _localizedStrings['colorOrange'] ?? 'Orange';
|
||||
String get colorRed => _localizedStrings['colorRed'] ?? 'Red';
|
||||
String get colorPurple => _localizedStrings['colorPurple'] ?? 'Purple';
|
||||
|
||||
// 날짜 형식 관련 getter
|
||||
String get dateFormatFull => _localizedStrings['dateFormatFull'] ?? 'MMM dd, yyyy';
|
||||
String get dateFormatShort => _localizedStrings['dateFormatShort'] ?? 'MM/dd';
|
||||
|
||||
// USD 환율 표시 형식
|
||||
String get exchangeRateDisplay => _localizedStrings['exchangeRateDisplay'] ?? '\$1 = @';
|
||||
|
||||
// 라벨 및 힌트 텍스트
|
||||
String get labelServiceName => _localizedStrings['labelServiceName'] ?? 'Service Name';
|
||||
String get hintServiceName => _localizedStrings['hintServiceName'] ?? 'e.g. Netflix, Spotify';
|
||||
String get labelMonthlyExpense => _localizedStrings['labelMonthlyExpense'] ?? 'Monthly Expense';
|
||||
String get labelNextBillingDate => _localizedStrings['labelNextBillingDate'] ?? 'Next Billing Date';
|
||||
String get labelWebsiteUrl => _localizedStrings['labelWebsiteUrl'] ?? 'Website URL (Optional)';
|
||||
String get hintWebsiteUrl => _localizedStrings['hintWebsiteUrl'] ?? 'https://example.com';
|
||||
String get labelEventPrice => _localizedStrings['labelEventPrice'] ?? 'Event Price';
|
||||
String get hintEventPrice => _localizedStrings['hintEventPrice'] ?? 'Enter discounted price';
|
||||
String get labelCategory => _localizedStrings['labelCategory'] ?? 'Category';
|
||||
|
||||
// 기타 번역
|
||||
String get subscription => _localizedStrings['subscription'] ?? 'Subscription';
|
||||
String get movie => _localizedStrings['movie'] ?? 'Movie';
|
||||
String get music => _localizedStrings['music'] ?? 'Music';
|
||||
String get exercise => _localizedStrings['exercise'] ?? 'Exercise';
|
||||
String get shopping => _localizedStrings['shopping'] ?? 'Shopping';
|
||||
String get currency => _localizedStrings['currency'] ?? 'Currency';
|
||||
String get websiteInfo => _localizedStrings['websiteInfo'] ?? 'Website Information';
|
||||
String get cancelGuide => _localizedStrings['cancelGuide'] ?? 'Cancellation Guide';
|
||||
String get cancelServiceGuide => _localizedStrings['cancelServiceGuide'] ?? 'To cancel this service, please go to the cancellation page through the link below.';
|
||||
String get goToCancelPage => _localizedStrings['goToCancelPage'] ?? 'Go to Cancellation Page';
|
||||
String get urlAutoMatchInfo => _localizedStrings['urlAutoMatchInfo'] ?? 'If URL is empty, it will be automatically matched based on the service name';
|
||||
String get dateSelect => _localizedStrings['dateSelect'] ?? 'Select';
|
||||
|
||||
// 새로 추가된 getter들
|
||||
String get serviceInfo => _localizedStrings['serviceInfo'] ?? 'Service Information';
|
||||
String get newSubscriptionAdd => _localizedStrings['newSubscriptionAdd'] ?? 'Add New Subscription';
|
||||
String get enterServiceInfo => _localizedStrings['enterServiceInfo'] ?? 'Enter service information';
|
||||
String get addSubscriptionButton => _localizedStrings['addSubscriptionButton'] ?? 'Add Subscription';
|
||||
String get serviceNameRequired => _localizedStrings['serviceNameRequired'] ?? 'Please enter service name';
|
||||
String get amountRequired => _localizedStrings['amountRequired'] ?? 'Please enter amount';
|
||||
String get subscriptionDetail => _localizedStrings['subscriptionDetail'] ?? 'Subscription Detail';
|
||||
String get enterAmount => _localizedStrings['enterAmount'] ?? 'Enter amount';
|
||||
String get invalidAmount => _localizedStrings['invalidAmount'] ?? 'Please enter a valid amount';
|
||||
|
||||
// 결제 주기를 키값으로 변환하여 번역된 이름 반환
|
||||
String getBillingCycleName(String billingCycleKey) {
|
||||
switch (billingCycleKey) {
|
||||
case 'monthly':
|
||||
case '월간':
|
||||
case '月間':
|
||||
case '月付':
|
||||
return monthly;
|
||||
case 'weekly':
|
||||
case '주간':
|
||||
case '週間':
|
||||
case '周付':
|
||||
return weekly;
|
||||
case 'yearly':
|
||||
case '연간':
|
||||
case '年間':
|
||||
case '年付':
|
||||
return yearly;
|
||||
default:
|
||||
return billingCycleKey; // 매칭되지 않으면 원본 반환
|
||||
}
|
||||
}
|
||||
|
||||
// 카테고리 이름을 키로 변환하여 번역된 이름 반환
|
||||
String getCategoryName(String categoryKey) {
|
||||
switch (categoryKey) {
|
||||
case '음악':
|
||||
return categoryMusic;
|
||||
case 'OTT(동영상)':
|
||||
return categoryOttVideo;
|
||||
case '저장/클라우드':
|
||||
return categoryStorageCloud;
|
||||
case '통신 · 인터넷 · TV':
|
||||
return categoryTelecomInternetTv;
|
||||
case '생활/라이프스타일':
|
||||
return categoryLifestyle;
|
||||
case '쇼핑/이커머스':
|
||||
return categoryShoppingEcommerce;
|
||||
case '프로그래밍':
|
||||
return categoryProgramming;
|
||||
case '협업/오피스':
|
||||
return categoryCollaborationOffice;
|
||||
case 'AI 서비스':
|
||||
return categoryAiService;
|
||||
case '기타':
|
||||
return categoryOther;
|
||||
default:
|
||||
return categoryKey; // 매칭되지 않으면 원본 반환
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
|
||||
const AppLocalizationsDelegate();
|
||||
|
||||
@override
|
||||
bool isSupported(Locale locale) => ['en', 'ko'].contains(locale.languageCode);
|
||||
bool isSupported(Locale locale) => ['en', 'ko', 'ja', 'zh'].contains(locale.languageCode);
|
||||
|
||||
@override
|
||||
Future<AppLocalizations> load(Locale locale) async {
|
||||
return AppLocalizations(locale);
|
||||
final localizations = AppLocalizations(locale);
|
||||
await localizations.load();
|
||||
return localizations;
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
Reference in New Issue
Block a user