다국어
Flutter 애플리케이션의 로컬화(Localization)는 여러 언어를 지원하여 글로벌 사용자 경험을 향상시키는 중요한 기능입니다.
본 문서에서는 Flutter 기본 로컬화와 Easy Localization 패키지를 사용하여 로컬화를 구현하는 방법과 모범 사례를 설명드리겠습니다.
Flutter 기본 로컬화
Flutter는 flutter_localizations 패키지를 사용하여 기본적인 로컬화를 지원합니다.
주요 개념
ARB 파일
- 번역 문자열을 저장하는 파일 형식.
- JSON 형식과 유사하며, 각 키는 번역 문자열의 식별자로 사용됩니다.
localizationsDelegates
- 번역된 문자열을 제공하는 클래스입니다.
supportedLocales
- 애플리케이션에서 지원하는 언어 및 지역 목록을 정의합니다.
설치 및 초기 설정
1. 의존성 추가
flutter pub add flutter_localizations --sdk=flutter
flutter pub add intl2. pubspec.yaml 설정
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: any
flutter:
generate: true
assets:
- lib/l10n/3. ARB 파일 생성
lib/l10n/ 디렉토리를 생성하고 번역 파일 추가:
app_en.arb
{
"@@locale": "en",
"language": "English",
"helloWorld": "Hello World",
"twoLanguages": "This app supports 2 languages",
"changeLanguages": "Change Language"
}app_ko.arb
{
"@@locale": "ko",
"language": "한국어",
"helloWorld": "안녕하세요 세계",
"twoLanguages": "이 앱은 2개의 언어를 지원합니다",
"changeLanguages": "언어 변경"
}4. l10n.yaml 파일 생성
Flutter에서 다국어 지원을 설정할 때 l10n.yaml 파일을 생성하여 로컬화 설정을 정의할 수 있습니다. 아래는 synthetic-package 설정과 관련된 주요 내용과 해결 방법에 대한 설명입니다.
문제점
synthetic-package: true 기본값
- l10n.yaml 파일에 synthetic-package: false가 설정되지 않은 경우, Flutter는 기본적으로 이를 true로 간주합니다.
이 경우, 생성된 파일은 .dart_tool/flutter_gen 디렉토리에 저장됩니다. 이는 다음과 같은 문제를 일으킬 수 있습니다:
파일 접근 제한:
- 생성된 로컬화 파일 app_localizations.dart를
lib/generated/app_localizations.dart와 같이 명시적으로 접근할 수 없습니다.
Import 어렵습니다:
- .dart_tool/flutter_gen에 숨겨진 파일은 수동으로 import가 어려우며, Flutter가 내부적으로만 관리합니다.
해결 방법
synthetic-package: false 설정 추가
l10n.yaml 파일에 synthetic-package: false를 추가하면, 생성된 파일이 lib/generated/app_localizations.dart 경로에 저장됩니다.
이를 통해 파일 접근과 import가 보다 쉬워집니다.
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
synthetic-package: false5. 코드 생성
flutter gen-l10nGeneralStreams 클래스
GeneralStreams 클래스는 Flutter 애플리케이션에서 언어 변경과 같은 글로벌 상태 관리를 위해 설계되었습니다. 이 클래스는 **StreamController**를 활용하여 상태를 관리하며, 아래는 상세한 설명입니다.
코드
import 'dart:async';
import 'package:flutter/material.dart';
class GeneralStreams {
const GeneralStreams._();
static StreamController<Locale> languageStream = StreamController.broadcast();
}클래스 목적
- 애플리케이션에서 언어를 변경하거나 상태를 실시간으로 관리할 수 있도록 설계된 클래스입니다.
- StreamController를 활용하여 언어 상태를 다른 위젯들에 전달합니다.
구성 요소
GeneralStreams._():
- 정적 상태를 관리하기 위해 **
private constructor**를 사용합니다. - 클래스 외부에서 직접 인스턴스를 생성할 수 없도록 합니다.
StreamController:
- **
StreamController**는 스트림을 통해 언어 상태를 관리합니다. broadcast()메서드를 사용하여 여러 구독자가 동일한 스트림 데이터를 받을 수 있도록 설정합니다.
앱 코드 구현
main.dart
import 'package:flutter/material.dart';
import 'generated/app_localizations.dart';
import 'general_streams.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return StreamBuilder<Locale>(
stream: GeneralStreams.languageStream.stream,
initialData: const Locale('en'),
builder: (context, snapshot) {
return MaterialApp(
locale: snapshot.data,
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [
Locale('en'),
Locale('ko'),
],
home: const MyHomePage(),
);
},
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final localizations = AppLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(
title: Text(localizations.language),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(localizations.helloWorld),
Text(localizations.twoLanguages),
ElevatedButton(
onPressed: () {
if (localizations.localeName == 'en') {
GeneralStreams.languageStream.add(const Locale('ko'));
} else {
GeneralStreams.languageStream.add(const Locale('en'));
}
},
child: Text(localizations.changeLanguages),
),
],
),
),
);
}
}2. Easy Localization 패키지
Easy Localization은 JSON 파일을 활용하여 번역 문자열을 관리하며, 간단한 언어 변경 및 추가 번역 설정을 제공합니다.
설치 및 초기 설정
1. 의존성 추가
flutter pub add easy_localization2. pubspec.yaml 설정
flutter:
uses-material-design: true
assets:
- assets/translations/3. 번역 파일 생성
assets/translations/ 디렉토리를 생성하고 JSON 파일 추가:
en.json
{
"hello": "Hello",
"welcome": "Welcome to our app!"
}ko.json
{
"hello": "안녕하세요",
"welcome": "저희 애플리케이션에 오신 것을 환영합니다!"
}앱 코드 구현
main.dart
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await EasyLocalization.ensureInitialized();
runApp(
EasyLocalization(
supportedLocales: const [Locale('en'), Locale('ko')],
path: 'assets/translations',
fallbackLocale: const Locale('en'),
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('hello'.tr()),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('welcome'.tr()),
ElevatedButton(
onPressed: () {
context.setLocale(const Locale('ko'));
},
child: const Text('Change to Korean'),
),
ElevatedButton(
onPressed: () {
context.setLocale(const Locale('en'));
},
child: const Text('Change to English'),
),
],
),
),
);
}
}Best Practices
명확한 번역 키 사용
- 번역 키는 구조적이고 명확하게 작성해야 합니다.
예를 들어, home.welcome, settings.language와 같이 작성하면 관리와 사용이 용이합니다.
지역 및 언어 추가
- 글로벌 앱 개발 시 다양한 지역 및 언어 코드를 설정하는 것이 중요합니다.
- Locale('en', 'US') (영어, 미국), Locale('es', 'MX') (스페인어, 멕시코)
Fallback Locale 설정
- 번역 누락으로 인해 앱이 정상적으로 작동하지 않는 상황을 방지하려면 기본 언어를 설정해야 합니다.
기본 언어를 지정하면 특정 번역이 누락되더라도 기본값을 사용할 수 있습니다.
지속적인 번역 관리
- 앱이 업데이트될 때 새로운 번역 문자열을 추가하고 기존 번역 파일을 유지보수하는 것이 중요합니다.
이를 통해 번역 품질을 유지하고 사용자 경험을 향상시킬 수 있습니다.

