도움말 센터

Flutter 현지화: ARB 파일, Intl 및 자동화

Flutter의 내장 현지화 시스템은 ARB(Application Resource Bundle) 파일과 intl 패키지를 사용하여 모든 언어에서 완전히 네이티브한 경험을 제공합니다. 이 가이드에서는 프로젝트 설정 및 ARB 형식 세부 정보부터 언어 전환, 복수형 처리, l10n.dev를 통한 번역 자동화에 이르기까지 모든 내용을 다룹니다.

Flutter 현지화란 무엇인가요?

Flutter 현지화는 앱을 여러 언어 및 지역에 맞게 조정하는 공식적인 접근 방식입니다. 번역된 문자열을 저장하기 위해 ARB 파일을 사용하며, flutter_gen 코드 생성기를 통해 타입 안전한 Dart 접근자를 생성합니다. 런타임 시 Flutter는 기기 로캘에 따라 올바른 ARB 파일을 선택하며, 프로그래밍 방식으로 로캘을 전환할 때 재시작이 필요하지 않습니다.

프로젝트 설정

Flutter의 현지화 파이프라인은 pubspec.yaml과 l10n.yaml이라는 두 가지 구성 파일에 의해 구동됩니다. pubspec.yaml에서 코드 생성을 활성화하고 Flutter가 ARB 디렉토리를 가리키도록 설정하세요.

1. pubspec.yaml 업데이트

flutter_localizations와 intl을 의존성으로 추가한 다음, generate 플래그를 활성화하여 Flutter가 ARB 파일로부터 Dart 현지화 클래스를 자동으로 생성하도록 하세요.

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  intl: any

flutter:
  generate: true

2. l10n.yaml 생성

프로젝트 루트에 l10n.yaml 파일을 배치하여 ARB 디렉토리, 템플릿 파일 및 생성된 출력 파일 이름을 구성하세요.

arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart

ARB 파일 형식

ARB(Application Resource Bundle)는 Flutter 국제화를 위해 특별히 설계된 JSON 기반 형식입니다. 각 키는 번역 가능한 문자열에 매핑되며, 선택적 메타데이터 키(@로 시작)는 번역자를 위한 설명, 플레이스홀더 정의 및 컨텍스트를 담고 있습니다.

  • @@locale: 파일의 로캘을 선언합니다(예: "en", "fr", "zh_CN"). l10n.dev는 이를 대상 언어 코드로 자동 업데이트합니다.
  • @@last_modified: 마지막 수정 타임스탬프입니다. l10n.dev는 번역된 파일을 생성할 때 이를 현재 UTC 타임스탬프로 자동 설정합니다.
  • @key 메타데이터: 설명, 예시 및 플레이스홀더와 같은 메타데이터 항목은 기본적으로 번역되지 않으며, 번역자를 위한 컨텍스트를 보존하기 위해 변경되지 않은 상태로 유지됩니다. 이 항목들을 번역하려면 translateMetadata 설정을 활성화하세요.
  • 플레이스홀더 및 ICU 메시지: 문자열에는 명명된 플레이스홀더({name})와 복수형 및 선택을 위한 ICU 메시지 구문이 포함될 수 있으며, 이 모든 것은 번역 과정에서 올바르게 보존됩니다.

소스 ARB 파일 (영어)

{
  "@@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"
      }
    }
  }
}

번역된 ARB 파일 (프랑스어)

번역 후 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는 언어 코드와 지역 코드를 구분하기 위해 밑줄을 사용합니다.

ARB 파일은 하이픈이 아닌 밑줄을 사용합니다. app_en-US.arb나 app_zh-CN.arb가 아닌 app_en_US.arb 및 app_zh_CN.arb로 작성하세요.
# 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.dart

초기화

localizationsDelegates와 supportedLocales를 제공하여 생성된 Dart 현지화 클래스를 MaterialApp과 연결하세요. 그러면 Flutter가 기기 로캘에 맞는 올바른 ARB 데이터를 확인합니다.

MaterialApp 설정

생성된 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 복수형 범주를 처리하며, 대상 언어 규칙에 따라 자동으로 올바른 형식을 적용합니다.

  • ARB 문자열 값 내에서 {count, plural, =0{...} =1{...} other{...}} 구문을 사용하세요.
  • @key 메타데이터에서 count 플레이스홀더를 int 타입으로 선언하세요.
  • l10n.dev는 아랍어, 러시아어, 폴란드어와 같이 복잡한 언어를 포함하여 각 대상 언어에 필요한 모든 복수형 형식을 수동 개입 없이 생성합니다.
{
  "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의 완벽한 ARB 지원

l10n.dev는 Flutter의 ARB 워크플로우와 원활하게 작동하도록 특별히 제작되었습니다. 소스 ARB 파일을 업로드하고 정확하고 올바르게 구조화된 번역본을 받아보세요:

  • 자동 메타데이터 업데이트: @@locale은 대상 언어 코드로 업데이트되며, @@last_modified는 현재 UTC 타임스탬프로 자동 설정됩니다.
  • 메타데이터 번역 제어: 기본적으로 @key 메타데이터 항목(설명, 예시, 컨텍스트)은 번역되지 않으며 번역자 노트가 유지되도록 변경되지 않습니다. UI 문자열과 함께 번역하려면 translateMetadata 설정을 활성화하세요.
  • 사용자 지정 파일 접두사: app_en.arb, my_app_en_US.arb, strings_fr.arb 등 모든 명명 패턴이 지원됩니다.
  • 밑줄 로캘 형식: ARB 로캘 코드는 하이픈 대신 밑줄(en_US, zh_CN)을 사용합니다. l10n.dev는 이를 올바르게 처리하므로 생성된 파일을 Flutter 프로젝트에 바로 사용할 수 있습니다.
  • 복수형 인식: ICU 복수형 형식은 CLDR 규칙에 따라 모든 대상 언어에 대해 생성되므로 번역 후 수동으로 복수형을 편집할 필요가 없습니다.

npm을 통한 번역 자동화

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,ko

Flutter 빌드 통합

ai-l10n을 Flutter 빌드 프로세스에 직접 연결하여 앱이 컴파일되기 전에 항상 번역이 최신 상태로 유지되도록 할 수 있습니다. 두 가지 일반적인 접근 방식은 package.json 스크립트 또는 Makefile을 사용하는 것입니다.

package.json 스크립트를 통한 방법

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"
  }
}

Makefile을 통한 방법

팀에서 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 web

CI/CD 통합, 증분 업데이트, 여러 파일에 걸친 일괄 번역 및 GitHub 액션 워크플로우 예시는 다음을 참조하세요.현지화 자동화 가이드.

VS Code 확장 프로그램

l10n.dev VS Code 확장 프로그램은 Flutter ARB 번역을 에디터 안으로 직접 가져옵니다. VS Code를 떠나지 않고도 ARB 파일을 마우스 오른쪽 버튼으로 클릭하여 대상 언어로 번역하세요.

VS Code에서 작동 방식:

  1. 에디터에서 소스 ARB 파일(예: app_en.arb)을 엽니다.
  2. 에디터에서 마우스 오른쪽 버튼을 클릭하고 "Translate JSON"을 선택합니다.
  3. 하나 이상의 대상 언어(예: 프랑스어, 일본어, 독일어)를 선택합니다.
  4. 확장 프로그램은 @@locale 및 @@last_modified가 자동으로 업데이트된 현지화된 ARB 파일을 소스 파일과 함께 생성합니다.

실제 작동 모습 확인

VS Code 내에서 Flutter ARB 파일을 우즈베크어로 번역하는 실시간 예시입니다:

Flutter ARB localization in VS Code

Flutter 앱 현지화 시작하기

전 세계 사용자에게 다가갈 준비가 되셨나요? l10n.dev 작업 공간에서 직접 ARB 파일을 번역하거나, npm 명령줄 인터페이스로 자동화하거나, VS Code 내에서 바로 번역할 수 있습니다: