[Flutter] Localizations 완전 정복 하기

Seong-Am Kim
19 min readJan 11, 2022

--

Flutter에서 Localization(현지화)를 하는 방법은 수 없이 많다.

Javascript 에서는 i18n 패키지를 가지고 주로 이를 달성하지만 Flutter에서는 다소 여러 방법으로 파편화되어 있다.

오늘은 오픈소스인 flutter_boilerplate를 작업하는 과정에서 Location을 적용하면서 학습 했던 과정들을 공유하고자 한다.

Photo by Sigmund on Unsplash

해당 글은 다음과 같은 순서로 진행된다.

  1. Localization을 달성하기 여러 방법
  2. 현지화의 기본이 되는 flutter_localizations에 대한 설명
  3. 직접 구현을 통한 현지화
  4. flutter_localizationos + intl을 이용한 현지화
  5. flutter_localizationos + intl을 쉽고 빠르게 구현하기
  6. 기타 다른 패키지를 이용한 현지화 (easy_localization, get 등)

여러 적용방법들이 있지만 빠르게 Localization을 달성하고 싶으신 분이라면 바로 5번 flutter_localizationos + intl을 쉽고 빠르게 구현하기 넘어가면 된다.

필자가 생각하기엔 가장 쉬운 방법이면서도 공식 Flutter 홈페이지에서도 추천하는 방법을 따를 수 있기 때문이다.

Flutter에선 아래의 방법을 통해 Localization이 가능하다

  1. flutter_localizationos + custom (직접 구현)
  2. flutter_localizationos + intl
  3. easy_localization

각각의 방법들은 flutter_localizations을 기반으로 JSON, CSV, Yaml, Xml 또는 arb 파일을 이용한다.

그 중 2번의 경우 Flutter 공식 홈페이지에서 소개된 방법들인데 이는 arb 파일을 가지고 Localization을 달성한다.

다른 확장자의 경우 비교적 익숙하나 arb의 경우 대부분 개발자에겐 생소하기에 우선 이를 간략히 설명하고자 한다.

arb란 Application Resource Bundle의 약자로 구글에서 만든 localization 을 달성하기 위해 만든 것이다. 형태는 json과 같이 key, value로 이루어져 있다.

{
"@@locale": "en",

"appName": "dooboolab"
}

보다 자세히 알고 싶은 분은 아래 Git 위키에 가시면 확인이 가능하다.

flutter_localizations

flutter_localizations은 Flutter에서 현지화를 이용하고 싶을때 기본이 되는 것으로 easy_localization등 많은 패지지들도 내부적으론 이를 이용하도록 추상화되어 있다.

우선 설정 방법을 먼저 살펴보자.

pubspec.yaml 파일을 아래와 같이 수정한다.

dependencies:
flutter:
sdk: flutter
flutter_localizations: # Add this line
sdk: flutter # Add this line

다음 pub get package 명령어를 통해 이를 설치해준다.

그리고 앱의 메인 되는곳으로 이동하여 다음과 같이 수정해준다.

import 'package:flutter_localizations/flutter_localizations.dart';...return const MaterialApp(
title: 'Localizations Sample App',
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
Locale('en', ''), // English, no country code
Locale('ko', ''), // Korean, no country code
],
home: MyHomePage(),
);

위에 대해 간략히 설명하자면 localizationsDelegates 경우 쉽게 이야기 하자면 현지화의 기능이 들어 간다고 보면 된다. GlobalWidgetsLocalizations.delegate 의 경우 현지화된 문자열의 값을 제공하는 것이고 GlobalWidgetsLocalizations.delegate 경우 텍스트의 방향 (왼쪽에서 오른쪽 또는 오른쪽에서 왼쪽)을 정의 하는 것이다.

이제 현지화에 대한 정의를 Flutter에 해줬다면 두가지 선택지로 나뉜다.

  1. Custom하게 직접 구현 할 것인가.
  2. intl 패지지를 이용할 것인가.

두가지 모두 앞서 설정했던 flutter_localizations 기반으로 하므로 이를 설정해주는 것이 반드시 선행되어야 한다

직접 구현을 통한 현지화.

해당 방법은 Hyo님의 코드로 부터 공부한 것을 소개 해드린 것임을 알린다.

기본 개념은 LocalizationDelegate를 이용한 방법으로 번역 파일을 직접 불러와 현지화를 달성한다.

Flutter 에선 LocalizationsDelegate을 직접 구현 할 수 있도록 제공해준다. 이를 상속받아 앞서 flutter_localizations에서 추가했던 localizationsDelegates에 등록해주기만 하면 현지화에 대한 이벤트 정보를 수신할 수가 있다.

우선 이를 위해 LocalizationDelegate를 상속받아 구현하는 것이 필요한데 이를 코드를 살펴보면 아래와 같다.

여기서 핵심이 되는 부분은 LocalizationDelegate 클래스의 load 메소드 인데 디바이스에 현지화에 대한 정보가 로드가 될때(디바이스에 설정된 언어, 코드 등) 해당 메소드가 호출된다.

해당 정보를 Localizaton 클래스의load 메소드에서 불러올 번역 정보의 파일을 바인딩 시키면 어떤 번역 파일을 가져올지를 정할 수 있는 것이다.

위의 예제에서는 json 파일을 불러오도록 했으나 이론상으로 json 말고도 다른 다양한 형식의 파일을 불러오는 것이 가능하다.

당연한 이야겠지만 각각의 현지화의 맞게 json 파일이 생성되어 있어야 한다.

예를 들어 아래와 같이 json 파일이 있어야 한다.

경로: res/langs/en.json

{ 
"INTRO": "Create App!"
}

이후 실제 사용할 때는 Localization 클래스의 trans 메소드를 이용해 코드를 적어주면 현지화가 적용되어 디바이스에 표기된다.

Text(
Localization.of(context).trans('INTRO')
)

해당 설명이 부족해서 코드를 좀 더 보고 싶으신 분은 해당 코드가 구현된flutter_boilerplate의 링크를 남겨둘테니 참고하셨으면 좋겠다.

intl 패지지를 이용한 방법 (공식 홈페이지)

해당 방법은 공식 홈페이지에도 소개되어 있는 방법인데 진행다보면 상당히 까다로운 요소가 몇가지가 있다.

우선 공식 홈페이지에서 설명하는 방법대로 진행 하고 그 뒤 불편한 부분을 해소하기 위한 방법을 소개하겠다.

패키지 설치를 위해 우선 pubspec.yaml에 추가 해준다.

dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: ^0.17.0 # Add this line

해당 방법은 arb를 이용하기에 이를 Flutter에서 이용하기 위해선 별도의 코드 Generate가 되어야 한다.

이를 위해 pubspec.yaml에 해당 부분을 추가해야 한다.

# The following section is specific to Flutter.
flutter:
generate: true # Add this line

여기서 유의할 점은 dependencies의 flutter가 아닌 최상위가 flutter로 된 별도의 부분이 있으니 거기에 추가해야한다.

다음으로 프로젝트의 루트에 l10n.yaml 파일을 추가하고 아래 내용을 입력한다.

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

해당 파일은 코드를 Generate 할때 정보를 제공하기 위함이다.

이제 위에 설정한 경로에 맞게 arb 파일을 생성 해준다.

경로: ${FLUTTER_PROJECT}/lib/l10n/app_en.arb

{
"helloWorld": "Hello World!",
"@helloWorld": {
"description": "The conventional newborn programmer greeting"
}
}

해당 방법도 마찬가지로 localizationDelegates를 이용하는 것이기에 앱의 메인의 localizationsDeleagtes에 추가해줘야 한다.

import 'package:flutter_gen/gen_l10n/app_localizations.dart';
...
return const MaterialApp(
title: 'Localizations Sample App',
localizationsDelegates: [
AppLocalizations.delegate, // Add this line
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
Locale('en', ''), // English, no country code
Locale('ko', ''), // Korean, no country code
],
home: MyHomePage(),
);

이제 이를 활용하기 위해선 아래와 같은 문법으로 적어주면 된다.

Text(AppLocalizations.of(context)!.helloWorld);

여기까지가 공식 홈페이지에 소개된 intl을 이용한 구현 방법이다.

하지만 위의 방법들은 모두 context를 통과시켜 줘야 한다는 불편함이 있다.

그리고 intl 패키지는 해당 방법이 아닌 다른 방법으로 소개되어 있는데 지금 부터 그것을 소개 하고자 한다.

intl 패지지에서 설명하는 방법

arb 자체는 Flutter에서 읽을 수가 없다. 따라서 이를 dart 파일로 변환하는 과정이 필요한데 공식 홈페이지에서 소개된 방법은 .dart_tool/flutter_gen/gen_l10n의 경로에 가보면 dart파일이 생성된 것을 확인 해 볼 수가 있다.

이와 유사하게 별도의 dart파일을 만드는 것이 가능한데 arb파일을 생성하고 거기서 dart파일을 뽑아내는 것이다.

그 반대로 dart파일에서 arb 파일을 가져오는것 역시 가능하다.

이를 달성하기 위해선 별도의 commandline 패키지가 필요한데 intl에선 intl_translation 패키지를 소개하고 있다.

하지만 2022.01.11일 기준으로 해당 패키지는 최신버전인 intl 0.17 버전과의 호환성 문제로 설치가 되지 않는다.

해당 이슈는 아래 링크를 참고 바란다.

이슈를 해결하기 위해 intl_translation이 아닌 intl_generator패키지 를 이용하면 정상적으로 설치가 가능하며 사용법 또한 동일하다.

아래 명령어로 해당 패키지를 설치해준다

flutter pub add intl_generator --dev

이 후 아래 링크와 같이 코드를 작성해주면 된다.

앞서 설명 했듯이 dart 파일에서 arb 파일을 뽑아내는 것이 가능하다고 했는데

아래 명령어를 통해 가능하다.

flutter pub run intl_generator:extract_to_arb --output-dir=lib/l10n lib/main.dart

이렇게 되면 intl_messages.arb 란 arb 파일이 생성이 되게 되는데 해당 파일을 복사하여 각각 현지화에 맞게 intl_ko.arb 또는 intl_en.arb 등으로 생성해서 활용할 수 있다.

하지만 해당 arb만 가지고선 context 없이 사용이 불가한데 이를 해결하기 위해 arb에서 dart로 변환하는 것이 필요하다.

아래 명령어를 통해 각각의 arb 파일을 dart 파일로 변환시켜 주자

flutter pub run intl_generator:generate_from_arb --output-dir=lib/l10n --no-use-deferred-loading lib/main.dart lib/l10n/intl_*.arb

여기 까지 오게 되면 각각의 arb 파일마다 mssage_${value} 이런 형태로 생성되게 되는데 여기까지 온다면 context 없이 지역화를 달성할 수 있다.

사용 방법은 아래와 같다.

import 'package:intl/intl.dart';Text(Intl.message('appName'))

해당 방법은 context 없이 사용할 수 있기는 하나 지나치게 복잡하고 보다 근본적인 문제로 지역화를 위한 텍스트를 수정할 때마다 generator를 해줘야 하는 매우 큰 문제가 있다. 이를 해결하기 위해서 다음 방법을 소개 하고자 한다.

flutter_localizationos + intl을 쉽고 빠르게 구현하기

위와 같은 복잡한 설정을 자동화 하는 방법이 있는데 이는 Flutter Intl 이라는 Extension을 이용하는 것이다.

Visual studio code 와 Android studio 에서 모두 사용 가능하다.

해당 Extension은 intl_generator 의 설치 없이 dart 파일의 변환하는 과정을 자동화 해준다.

필자는 VSCode를 중심으로 설명하지만 Android 에서도 모두 과정은 동일하다.

Ctrl + P 를 입력하고 아래와 같이 >Flutter Intl: Initialize 을 입력하고 해당 메뉴를 선택한다.

참고로 Android studio에서는 Flutter Intl 플러그인 설치 후 해당 메뉴에서 선택 가능하다.

Android studio

잠시 뒤 필요한 파일을 빌드하게 되면 아래 사진과 같은 파일들이 생성된다.

여기서 l10n 하위 arb 확장자의 파일들을 수정하여 localization 작업을 진행하면 되며 ko 파일등 다른 localization 파일들이 필요할시엔 Ctrl + P 를 입력하고 >Flutter Intl: Add local 을 통해 추가 하도록 한다.

한가지 놀라운 점은 자동으로 intl_generator 의 설치 없이 Dart 파일의 변환하는 과정을 자동화 해준다는 것인데 arb 파일을 저장하면 모든 과정을 별도의 처리 없이 Dart로 변환해준다.

변환할 arb 파일
변환된 Dart 파일

해당 방법도 localizationDelegates를 이용하는 것이기 때문에 메인 되는 Dart 파일을 아래와 같이 수정해줘야 한다.

import 'package:flutter_boilerplate/generated/l10n.dart';return MaterialApp(
localizationsDelegates: const [
S.delegate, // Add this line!
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [
Locale('en', ''),
Locale('ko', ''),
],

이후 아래와 같이 사용할 수 있다.

import 'package:intl/intl.dart';Text(Intl.message('title'))

훨씬 간단하지 않는가?

Dart 파일 생성 또한 자동으로 해주니 매우 편하다고 개인적으로 생각한다.

Flutter Intl Extension 은 Intl 패키지를 활용해서 만든 것으로 Localizely라는 곳에서 관리하는 것으로 보인다.

일정 비용을 지불하면 웹에서 통합적으로 Localization을 관리할 수 있게 만들어 준다.

(해당글은 Localizaely의 광고글이 아니니 오해 없으셨으면 좋겠다. 위의 소개드린 기능은 무료로 이용 가능하다.)

Dart 파일을 변환을 자동화 해주는 것에서 큰 장점이 있다고 생각한다.

기타 다른 패키지를 이용한 현지화

그 밖에 Localization을 달성하기 위해 많은 패키지들이 있다. 사용 방법에 대해선 각각의 패지들이 잘 설명하고 있으니 참고 하셨으면 좋겠다.

  • easy_localization
  • get

참고로 get의 경우 localization을 만을 위한 패키지는 아니며 상태관리 및 네비게이션등 다양한 기능을 포함하고 있다. 그 중 현지화도 있다.

  • fast_i18n

이상이 Flutter 에서 Localization 을 달성하기 위한 방법들이다.

개인적으로 공식 홈페이지에서 소개하고 있고 본인의 스타일에 맞게 수정 가능한 intl의 방법이 가장 이상적이라고는 생각한다.

하지만 설정이 까다롭고 이를 이해하는데 있어서 러닝 커브가 있는것이 단점이 있으므로 이를 잘 판단 하여 무엇을 선택할지는 본인의 몫이라고 전하고 싶다.

--

--