코드가 더 복잡해 지기 전에 다국어 지원을 위한 구현을 추가해보자. 늦으면 늦을 수록 귀찮아 진다. ㅎ;
1. Easy Localization 패키지 추가
다국어 지원을 쉽게 도와주는 easy localization 패키지를 사용할 계획이니 pubspec.yaml 에 의존성을 추가하자.
...
dependencies:
flutter:
sdk: flutter
url_launcher: ^5.7.10
easy_localization: ^2.3.3 # 다국어 패키지 추가
...
2. 다국어 리소스 추가
assets 아래에 translations 폴더를 생성하고 언어별 리소스를 추가한다.
영어 (en.json), 스페인어 (es.json), 일본어 (ja.json), 한국어 (ko.json), 중국어 (zh.json) 를 추가했다.
앱에 사용된 문자열은 제목인 '오늘 우주는' 과 '앱 평가하기' 이므로 각각 'title', 'rate' 라는 이름으로 언어별 리소스를 작성하자.
한국어: ko.json
{
"title": "오늘 우주는",
"rate": "앱 평가하기"
}
영어: en.json
{
"title": "Space Daily",
"rate": "Rate this app"
}
스페인어: es.json
{
"title": "El Universo Hoy",
"rate": "Califica esta aplicación"
}
일본어: ja.json
{
"title": "今日の宇宙",
"rate": "アプリを評価"
}
중국어: zh.json
{
"title": "今天的宇宙",
"rate": "评价我们"
}
그리고 pubspec.yaml 의 flutter > assets 속성으로 리소스 폴더를 등록한다.
...
flutter:
uses-material-design: true
fonts:
- family: NexonLv2GothicLight
fonts:
- asset: assets/fonts/NEXON Lv2 Gothic Light.ttf
- family: NexonLv2GothicMedium
fonts:
- asset: assets/fonts/NEXON Lv2 Gothic Medium.ttf
assets:
- assets/translations/ # 다국어 리소스 폴더 추가
3. 다국어 지원 초기화
3.1. 기존 MaterialApp 을 Stateless 위젯으로 변경
기존에 runApp 에 넘기던 MaterialApp을 Stateless 위젯으로 일단 변경하고, 로케일 관련 설정을 build context로 부터 받아와서 설정한다. Stateless 위젯에 대한 설명은 아래 포스트를 참고하기 바란다.
Flutter 커스텀 위젯 (Stateless, Stateful)
기본적으로 플러터 UI 는 ListView, Column, Text 등 기본 위젯을 이용해서 구성한다. 하지만, 어플리케이션의 구현이 복잡해 질수록 재사용 가능한 커스텀 위젯의 개발이 불가피하다. 이번 포스트에서
drogrammer.tistory.com
lib/main.dart 를 아래와 같이 변경한다.
변경 전
import 'package:apod/view/contents.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
title: '오늘 우주는',
theme: ThemeData(
visualDensity: VisualDensity.adaptivePlatformDensity,
primaryColor: Colors.black,
fontFamily: 'NexonLv2GothicLight',
scaffoldBackgroundColor: Colors.black, // Scaffold 배경 색상 변경
appBarTheme: AppBarTheme(
centerTitle: true, // AppBar 의 타이틀을 중앙 정렬
),
),
home: Contents(),
));
}
변경 후
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '오늘 우주는',
// 로케일 delegate
localizationsDelegates: context.localizationDelegates,
// 지원하는 로케일
supportedLocales: context.supportedLocales,
// 설정된 로케일
locale: context.locale,
theme: ThemeData(
visualDensity: VisualDensity.adaptivePlatformDensity,
primaryColor: Colors.black,
fontFamily: 'NexonLv2GothicLight',
scaffoldBackgroundColor: Colors.black,
appBarTheme: AppBarTheme(
centerTitle: true,
),
),
home: Contents(),
);
}
}
3.1. EasyLocalization 초기화
lib/main.dart 파일의 runApp 함수에 MyApp 을 바로 넘기는 대신, EasyLocalization 위젯으로 한번 감싸고 넘기면 다국어 지원 초기화가 된다. EasyLocalizatoin 사용시 활용한 옵션은 아래와 같다.
- supportedLocales : 지원 로케일
- path : 다국어 리소스 위치
- fallbackLocale : 기본 로케일
- child : 루트 위젯. 기존의 MaterialApp 을 넘기면 된다.
import 'package:apod/view/contents.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
void main() {
runApp(
// 다국어 지원 위젯
EasyLocalization(
// 지원 언어
supportedLocales: [
Locale('en'),
Locale('es'),
Locale('ko'),
Locale('zh'),
Locale('ja'),
],
// 다국어 리소스 위치
path: 'assets/translations',
// 기본 로케일을 영어로 설정
fallbackLocale: Locale('en'),
// 루트 UI 위젯. 기존의 MyApp으로 설정
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '오늘 우주는',
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
theme: ThemeData(
visualDensity: VisualDensity.adaptivePlatformDensity,
primaryColor: Colors.black,
fontFamily: 'NexonLv2GothicLight',
scaffoldBackgroundColor: Colors.black,
appBarTheme: AppBarTheme(
centerTitle: true,
),
),
home: Contents(),
);
}
}
4. 다국어 적용
적용 방법은 간단하다. 적용 대상 리소스의 키에 tr() 이라는 함수를 호출하면 된다. 참고로 tr() 을 호출 하기 위해서는 아래 헤더를 추가해줘야 한다.
import 'package:easy_localization/easy_localization.dart';
변경할 문자열은 아래와 같다.
파일 위치 | 기존 문자열 | 변경 |
lib/main.dart | '오늘 우주는' | 'title'.tr() |
lib/contents.dart | '오늘 우주는' | 'title'.tr() |
lib/contents.dart | '앱 평가하기' | 'rate'.tr() |
변경한 코드는 아래와 같다.
lib/main.dart
import 'package:apod/view/contents.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
void main() {
runApp(
EasyLocalization(
supportedLocales: [
Locale('en'),
Locale('es'),
Locale('ko'),
Locale('zh'),
Locale('ja'),
],
path: 'assets/translations',
fallbackLocale: Locale('en'),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
// 제목 다국어 지원
title: 'title'.tr(),
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
theme: ThemeData(
visualDensity: VisualDensity.adaptivePlatformDensity,
primaryColor: Colors.black,
fontFamily: 'NexonLv2GothicLight',
scaffoldBackgroundColor: Colors.black,
appBarTheme: AppBarTheme(
centerTitle: true,
),
),
home: Contents(),
);
}
}
lib/contents.dart
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:easy_localization/easy_localization.dart';
class Contents extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// 제목 다국어 지원
title: Text('title'.tr()),
),
drawer: Drawer(
child: Container(
color: Colors.grey[900],
child: Column(
children: [
DrawerHeader(
child: Center(
child: Text(
// Drawer 제목 다국어 지원
'title'.tr(),
style: TextStyle(color: Colors.white, fontSize: 30),
),
),
decoration: BoxDecoration(color: Colors.black),
),
ListTile(
leading: Icon(Icons.star, color: Colors.white),
title: Text(
// 앱 평가하기 다국어 지원
'rate'.tr(),
style: TextStyle(color: Colors.white, fontSize: 20),
),
onTap: () {
_launchURL(
"https://play.google.com/store/apps/details?id=com.contextract.apod");
},
),
],
),
),
),
);
}
void _launchURL(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
print('Could not launch $url');
}
}
}
댓글