Flutter의 내장 현지화 시스템은 ARB(Application Resource Bundle) 파일과 intl 패키지를 사용하여 모든 언어에서 완전히 네이티브한 경험을 제공합니다. 이 가이드에서는 프로젝트 설정 및 ARB 형식 세부 정보부터 언어 전환, 복수형 처리, l10n.dev를 통한 번역 자동화에 이르기까지 모든 내용을 다룹니다.
Flutter 현지화는 앱을 여러 언어 및 지역에 맞게 조정하는 공식적인 접근 방식입니다. 번역된 문자열을 저장하기 위해 ARB 파일을 사용하며, flutter_gen 코드 생성기를 통해 타입 안전한 Dart 접근자를 생성합니다. 런타임 시 Flutter는 기기 로캘에 따라 올바른 ARB 파일을 선택하며, 프로그래밍 방식으로 로캘을 전환할 때 재시작이 필요하지 않습니다.
Flutter의 현지화 파이프라인은 pubspec.yaml과 l10n.yaml이라는 두 가지 구성 파일에 의해 구동됩니다. pubspec.yaml에서 코드 생성을 활성화하고 Flutter가 ARB 디렉토리를 가리키도록 설정하세요.
flutter_localizations와 intl을 의존성으로 추가한 다음, generate 플래그를 활성화하여 Flutter가 ARB 파일로부터 Dart 현지화 클래스를 자동으로 생성하도록 하세요.
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: any
flutter:
generate: true프로젝트 루트에 l10n.yaml 파일을 배치하여 ARB 디렉토리, 템플릿 파일 및 생성된 출력 파일 이름을 구성하세요.
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dartARB(Application Resource Bundle)는 Flutter 국제화를 위해 특별히 설계된 JSON 기반 형식입니다. 각 키는 번역 가능한 문자열에 매핑되며, 선택적 메타데이터 키(@로 시작)는 번역자를 위한 설명, 플레이스홀더 정의 및 컨텍스트를 담고 있습니다.
{
"@@locale": "en",
"@@last_modified": "2026-01-15T10:30:00Z",
"appTitle": "My App",
"@appTitle": {
"description": "The title of the application"
},
"welcome": "Welcome, {name}!",
"@welcome": {
"description": "Welcome message shown on the home screen",
"placeholders": {
"name": {
"type": "String",
"example": "Alice"
}
}
},
"unreadMessages": "{count, plural, =0{No unread messages} =1{1 unread message} other{{count} unread messages}}",
"@unreadMessages": {
"description": "Number of unread messages",
"placeholders": {
"count": {
"type": "int"
}
}
}
}번역 후 UI 문자열은 현지화되지만 메타데이터 구조는 그대로 유지됩니다. l10n.dev는 @@locale 및 @@last_modified를 자동으로 업데이트합니다.
{
"@@locale": "fr",
"@@last_modified": "2026-01-15T10:30:01Z",
"appTitle": "Mon Application",
"@appTitle": {
"description": "The title of the application"
},
"welcome": "Bienvenue, {name} !",
"@welcome": {
"description": "Welcome message shown on the home screen",
"placeholders": {
"name": {
"type": "String",
"example": "Alice"
}
}
},
"unreadMessages": "{count, plural, =0{Aucun message non lu} =1{1 message non lu} other{{count} messages non lus}}",
"@unreadMessages": {
"description": "Number of unread messages",
"placeholders": {
"count": {
"type": "int"
}
}
}
}ARB 파일은 간단한 명명 패턴을 따릅니다: 접두사(기본값 app_) 뒤에 로캘 코드와 .arb 확장자가 붙습니다. Flutter와 l10n.dev는 언어 코드와 지역 코드를 구분하기 위해 밑줄을 사용합니다.
# Default pattern (recommended)
app_en.arb
app_fr.arb
app_en_US.arb # Locale with region (underscore format)
app_zh_CN.arb # Chinese Simplified
# Custom prefix patterns also supported
my_app_en.arb
my_app_fr.arb
# Note: ARB files use underscores, not hyphens
# ✓ app_en_US.arb
# ✗ app_en-US.arb모든 ARB 파일을 lib/ 내의 전용 l10n 폴더에 정리하세요. Flutter의 코드 생성기는 l10n.yaml의 arb-dir 설정에 따라 자동으로 파일을 가져와 즉시 사용 가능한 Dart 클래스를 출력합니다.
lib/
├── l10n/
│ ├── app_en.arb ← Source (English)
│ ├── app_fr.arb ← French
│ ├── app_de.arb ← German
│ ├── app_ja.arb ← Japanese
│ ├── app_zh_CN.arb ← Chinese Simplified
│ └── app_es.arb ← Spanish
├── main.dart
└── ...
# Generated output (do not edit manually)
.dart_tool/
└── flutter_gen/
└── gen_l10n/
└── app_localizations.dartlocalizationsDelegates와 supportedLocales를 제공하여 생성된 Dart 현지화 클래스를 MaterialApp과 연결하세요. 그러면 Flutter가 기기 로캘에 맞는 올바른 ARB 데이터를 확인합니다.
생성된 AppLocalizations.delegate와 세 개의 Flutter SDK 델리게이트를 포함한 4개의 필수 델리게이트를 전달하고 앱이 지원하는 모든 로캘을 나열하세요. 번역된 문자열에 액세스하려면 위젯 트리 어디에서나 AppLocalizations.of(context)!를 사용하세요.
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
// Required delegates
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
// Supported locales
supportedLocales: AppLocalizations.supportedLocales,
home: const HomePage(),
);
}
}
// Use in a widget
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(title: Text(l10n.appTitle)),
body: Center(child: Text(l10n.welcome('Alice'))),
);
}
}Flutter를 사용하면 MaterialApp의 locale 속성을 업데이트하여 런타임에 앱 로캘을 전환할 수 있습니다. 일반적인 패턴은 StatefulWidget 또는 상태 관리 솔루션에 Locale을 유지하고 이를 변경하기 위한 콜백을 노출하는 것입니다. 위젯 트리는 새 로캘로 자동으로 다시 빌드됩니다.
// Manage locale state at the app level
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Locale _locale = const Locale('en');
void _changeLocale(Locale locale) {
setState(() => _locale = locale);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
locale: _locale,
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: AppLocalizations.supportedLocales,
home: SettingsPage(onLocaleChange: _changeLocale),
);
}
}
// Language selector widget
class LanguageSelector extends StatelessWidget {
final void Function(Locale) onLocaleChange;
const LanguageSelector({super.key, required this.onLocaleChange});
@override
Widget build(BuildContext context) {
return DropdownButton<Locale>(
value: Localizations.localeOf(context),
items: AppLocalizations.supportedLocales
.map((locale) => DropdownMenuItem(
value: locale,
child: Text(locale.toLanguageTag()),
))
.toList(),
onChanged: (locale) {
if (locale != null) onLocaleChange(locale);
},
);
}
}Flutter는 ARB 파일 내의 복수형 처리를 위해 ICU 메시지 구문을 사용합니다. intl 패키지는 모든 CLDR 복수형 범주를 처리하며, 대상 언어 규칙에 따라 자동으로 올바른 형식을 적용합니다.
{
"cartItems": "{count, plural, =0{Your cart is empty} =1{1 item in your cart} other{{count} items in your cart}}",
"@cartItems": {
"description": "Cart item count",
"placeholders": {
"count": { "type": "int" }
}
},
"daysLeft": "{days, plural, =1{1 day left} other{{days} days left}}",
"@daysLeft": {
"description": "Days remaining",
"placeholders": {
"days": { "type": "int" }
}
}
}l10n.dev는 Flutter의 ARB 워크플로우와 원활하게 작동하도록 특별히 제작되었습니다. 소스 ARB 파일을 업로드하고 정확하고 올바르게 구조화된 번역본을 받아보세요:
ai-l10n npm 패키지를 사용하여 명령줄에서 또는 CI/CD 파이프라인의 일부로 소스 ARB 파일을 번역하세요. 한 번 설치하면 단일 명령으로 여러 언어로 번역할 수 있습니다.
# Install the CLI
npm install ai-l10n
# Translate your source ARB to multiple languages
npx ai-l10n translate lib/l10n/app_en.arb \
--languages fr,de,ja,zh_CN,es,koai-l10n을 Flutter 빌드 프로세스에 직접 연결하여 앱이 컴파일되기 전에 항상 번역이 최신 상태로 유지되도록 할 수 있습니다. 두 가지 일반적인 접근 방식은 package.json 스크립트 또는 Makefile을 사용하는 것입니다.
translate 스크립트를 추가하고 npm의 prebuild 라이프사이클 훅을 사용하여 모든 빌드 전에 자동으로 실행되도록 하세요. npm run build:android (또는 build:ios / build:web)를 실행하면 ai-l10n이 먼저 번역한 다음 Flutter로 작업을 전달합니다.
{
"scripts": {
"translate": "ai-l10n translate lib/l10n/app_en.arb --languages fr,de,ja,zh_CN,es,ko --update",
"prebuild": "npm run translate",
"build:android": "flutter build apk",
"build:ios": "flutter build ios",
"build:web": "flutter build web"
}
}팀에서 Make를 사용하는 경우, translate 타겟을 선언하고 각 빌드 타겟이 이에 의존하도록 만드세요. make build-android (또는 build-ios / build-all)를 실행하면 flutter build를 호출하기 전에 모든 대상 언어가 번역됩니다.
LANGUAGES = fr,de,ja,zh_CN,es,ko
translate:
npx ai-l10n translate lib/l10n/app_en.arb --languages $(LANGUAGES) --update
build-android: translate
flutter build apk
build-ios: translate
flutter build ios
build-web: translate
flutter build web
build-all: translate
flutter build apk
flutter build ios
flutter build webCI/CD 통합, 증분 업데이트, 여러 파일에 걸친 일괄 번역 및 GitHub 액션 워크플로우 예시는 다음을 참조하세요.현지화 자동화 가이드.
l10n.dev VS Code 확장 프로그램은 Flutter ARB 번역을 에디터 안으로 직접 가져옵니다. VS Code를 떠나지 않고도 ARB 파일을 마우스 오른쪽 버튼으로 클릭하여 대상 언어로 번역하세요.
VS Code 내에서 Flutter ARB 파일을 우즈베크어로 번역하는 실시간 예시입니다:

전 세계 사용자에게 다가갈 준비가 되셨나요? l10n.dev 작업 공간에서 직접 ARB 파일을 번역하거나, npm 명령줄 인터페이스로 자동화하거나, VS Code 내에서 바로 번역할 수 있습니다:
l10n.dev를 사용하여 Flutter 앱을 현지화해 주셔서 감사합니다! 🚀
이 가이드가 도움이 되었다면, 전 세계 사용자에게 다가가야 하는 다른 Flutter 개발자들과 공유해 주세요.
함께 Flutter 앱을 더 포용적이고 세계 시장에 대비할 수 있도록 만들 수 있습니다.