feat(l10n): 국제화(L10n) 시스템 도입 및 하드코딩 텍스트 변환
- flutter_localizations 및 intl 패키지 추가 - l10n.yaml 설정 파일 및 app_ko.arb 메시지 파일 생성 - 모든 화면(app, front, game_play, new_character, save_picker)의 하드코딩 텍스트를 L10n 키로 변환 - 테스트 파일에 localizationsDelegates 추가하여 L10n 지원
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:askiineverdie/l10n/app_localizations.dart';
|
||||
|
||||
class FrontScreen extends StatelessWidget {
|
||||
const FrontScreen({super.key, this.onNewCharacter, this.onLoadSave});
|
||||
|
||||
@@ -107,7 +109,7 @@ class _HeroHeader extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Ascii Never Die',
|
||||
L10n.of(context).appTitle,
|
||||
style: theme.textTheme.headlineSmall?.copyWith(
|
||||
color: colorScheme.onPrimary,
|
||||
fontWeight: FontWeight.w700,
|
||||
@@ -126,14 +128,19 @@ class _HeroHeader extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: const [
|
||||
_Tag(icon: Icons.cloud_off_outlined, label: 'No network'),
|
||||
_Tag(icon: Icons.timer_outlined, label: 'Idle RPG loop'),
|
||||
_Tag(icon: Icons.storage_rounded, label: 'Local saves'),
|
||||
],
|
||||
Builder(
|
||||
builder: (context) {
|
||||
final l10n = L10n.of(context);
|
||||
return Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: [
|
||||
_Tag(icon: Icons.cloud_off_outlined, label: l10n.tagNoNetwork),
|
||||
_Tag(icon: Icons.timer_outlined, label: l10n.tagIdleRpg),
|
||||
_Tag(icon: Icons.storage_rounded, label: l10n.tagLocalSaves),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -151,6 +158,7 @@ class _ActionRow extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final l10n = L10n.of(context);
|
||||
|
||||
return Wrap(
|
||||
spacing: 12,
|
||||
@@ -159,7 +167,7 @@ class _ActionRow extends StatelessWidget {
|
||||
FilledButton.icon(
|
||||
onPressed: onNewCharacter,
|
||||
icon: const Icon(Icons.casino_outlined),
|
||||
label: const Text('New character'),
|
||||
label: Text(l10n.newCharacter),
|
||||
style: FilledButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 14),
|
||||
textStyle: theme.textTheme.titleMedium,
|
||||
@@ -168,7 +176,7 @@ class _ActionRow extends StatelessWidget {
|
||||
OutlinedButton.icon(
|
||||
onPressed: onLoadSave,
|
||||
icon: const Icon(Icons.folder_open),
|
||||
label: const Text('Load save'),
|
||||
label: Text(l10n.loadSave),
|
||||
style: OutlinedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 14),
|
||||
textStyle: theme.textTheme.titleMedium,
|
||||
@@ -177,7 +185,7 @@ class _ActionRow extends StatelessWidget {
|
||||
TextButton.icon(
|
||||
onPressed: () => _showPlaceholder(context),
|
||||
icon: const Icon(Icons.menu_book_outlined),
|
||||
label: const Text('View build plan'),
|
||||
label: Text(l10n.viewBuildPlan),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -189,11 +197,12 @@ class _StatusCards extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = L10n.of(context);
|
||||
return Column(
|
||||
children: const [
|
||||
children: [
|
||||
_InfoCard(
|
||||
icon: Icons.route_outlined,
|
||||
title: 'Build roadmap',
|
||||
title: l10n.buildRoadmap,
|
||||
points: [
|
||||
'Port PQ 6.4 data set (Config.dfm) into Dart constants.',
|
||||
'Recreate quest/task loop with deterministic RNG + saves.',
|
||||
@@ -203,7 +212,7 @@ class _StatusCards extends StatelessWidget {
|
||||
SizedBox(height: 16),
|
||||
_InfoCard(
|
||||
icon: Icons.auto_fix_high_outlined,
|
||||
title: 'Tech stack',
|
||||
title: l10n.techStack,
|
||||
points: [
|
||||
'Flutter (Material 3) with multiplatform targets enabled.',
|
||||
'path_provider + shared_preferences for local storage hooks.',
|
||||
|
||||
Reference in New Issue
Block a user