본문 바로가기
mobile/flutter

[Flutter] 플루터에 다국어(i18n) 적용 (use intl package)

by moonsiri 2021. 3. 4.
728x90
반응형

플루터에 i18n을 적용하려고 합니다.

지원하는 패키지는 intl, flutter_i18n, easy_localization 등이 있는데, publisher가 dart.dev인 intl 패키지를 사용하겠습니다.

intl은 dart에서 internalization and localization를 지원하는 패키지입니다. 다국어 처리나 성별, 날짜, 숫자 등을 그 지역이나 국가에 맞게 바꿀 때 사용합니다.

 

간단하게 설명하자면 dart code를 arb로 generate 하고 변환한 arb 파일을 다시 dart로 변환하여 다국어 적용을 합니다.

arb란 Application Resource Bundle로 구글에서 만든 파일 형식입니다.

(key:value 형식을 원하시면 easy_localization 패키지를 확인)

 

우선 pubspec.yaml에 dependency를 추가합니다.

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter

  intl: ^0.16.1

dev_dependencies:
  flutter_test:
    sdk: flutter

  intl_translation: ^0.17.10+1

 

key로 사용할 변수들을 담은 messages.dart를 작성하겠습니다. name과 변수명은 같아야합니다.

import 'package:intl/intl.dart';

class Messages {
  String get appName => Intl.message(
    "Flutter APP",
    name: "appName"
  );
  
  String get helloWorld => Intl.message(
    "Hello, World!",
    name: "helloWorld"
  );

  hello(str) => Intl.message(
      "Hello, $text!",
      name: "hello",
      args: [str]
  );
}

 

그다음은 intl message를 .arb로 추출해야 하는데요. intl_translation 패키지는 arb를 만드는 명령어를 지원합니다.

flutter pub run intl_translation:extract_to_arb --output-dir=[추출한 arb 파일이 저장될 경로] [arb를 추출할 dart 파일]

flutter pub run intl_translation:extract_to_arb --output-dir=assets/i18n lib/i18n/messages.dart

 

위 명령어를 실행하면 intl_messages.arb 파일이 assets/i18n 폴더 하위에 생성됩니다.

{
  "@@last_modified": "2021-03-04T20:04:17.732096",
  "appName": "Flutter APP",
  "@appName": {
    "type": "text",
    "placeholders": {}
  },
  "helloWorld": "Hello, World!",
  "@helloWorld": {
    "type": "text",
    "placeholders": {}
  },
  "hello": "Hello, {str}!",
  "@hello": {
    "type": "text",
    "placeholders": {
      "str": {}
    }
  }
}

messages.dart에서 정의했던 Intl.messages()들이 json형태로 바뀌었습니다.

이제 intl_messages.arb을 복사하여 언어별로 파일을 생성합니다.

  • intl_en.arb
  • intl_ko.arb
{
  "@@last_modified": "2021-03-04T20:04:17.732096",
  "appName": "플루터 APP",
  "@appName": {
    "type": "text",
    "placeholders": {}
  },
  "helloWorld": "안녕, 세상!",
  "@helloWorld": {
    "type": "text",
    "placeholders": {}
  },
  "hello": "안녕, {str}!",
  "@hello": {
    "type": "text",
    "placeholders": {
      "str": {}
    }
  }
}

 

arb 파일이 생성되었으면 끝인가? 아닙니다. arb 파일을 직접 사용하진 못하고 플루터에서 사용할 수 있게 dart파일로 변경해줘야 합니다.

 

arb파일을 변환하려면 역시 intl_translation에서 지원하는 명령어를 사용해야 합니다.

flutter pub run intl_translation:generate_from_arb --output-dir=[저장될 경로] --no-use-deferred-loading [문자열이 있는 dart파일] [다국어 arb 파일들]

# windows
flutter pub run intl_translation:generate_from_arb --output-dir=lib/i18n --no-use-deferred-loading lib/i18n/messages.dart assets/i18n/intl_ko.arb assets/i18n/intl_en.arb

# mac, linux
flutter pub run intl_translation:generate_from_arb --output-dir=lib/i18n --no-use-deferred-loading lib/i18n/messages.dart assets/i18n/intl_*.arb

위 명령어를 실행하면 lib/i18n 하위에 messages_all.dart, messages_ko.dart, messages_en.dart가 생성됩니다.

 

 

다국어 적용은 LocationDelegate 클래스를 사용해야 합니다. 번역된 message들을 읽어 들이고, 어떤 언어를 지원하는지 알아내서 적용합니다.

lib/i18n/localizations.dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

import 'messages_all.dart';

class AppLocalizations {
  static Future<AppLocalizations> load(Locale locale) {
    final String name = locale.countryCode == null ? locale.languageCode : locale.toString();
    final String localeName = Intl.canonicalizedLocale(name);

    return initializeMessages(localeName).then((bool _ ) {
    Intl.defaultLocale = localeName;
    return new AppLocalizations();
    });
  }

  static AppLocalizations of(BuildContext context) {
    return Localizations.of<AppLocalizations>(context, AppLocalizations);
  }
}

class AppLocalizationDelegate extends LocalizationsDelegate<AppLocalizations> {

  @override
  bool isSupported(Locale locale) {
    return ['en', 'ko'].contains(locale.languageCode);
  }

  @override
  Future<AppLocalizations> load(Locale locale) {
    return AppLocalizations.load(locale);
  }

  @override
  bool shouldReload(LocalizationsDelegate<AppLocalizations> old) {
    return false;
  }
}

 

AppLocalizationDelegate()를 위젯에 적용해보도록 하겠습니다.

MaterialApp()의 localizationsDelegates 속성과 supportedLocales 속성을 바꿔줘야 합니다.

lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'i18n/localizations.dart';
import 'i18n/messages.dart';

void main() => {
  runApp(MyApp());
}

final msg = Messages();

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      localizationsDelegates: [
        AppLocalizationDelegate(),
        GlobalMaterialLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,   // https://moonsiri.tistory.com/119
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: [Locale("en"), Locale("ko")],
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: msg.hello('Flutter')),
    );
  }
}

 

 

완성된 파일 구조는 다음과 같습니다.

project
  │
  └─ assets
       └─ i18n
            └─ intl_en.arb
            └─ intl_ko.arb
            └─ intl_messages.arb
  │
  └─ lib
       └─ i18n
            └─ localization.dart
            └─ messages.dart
            └─ messages_all.dart
            └─ messages_en.dart
            └─ messages_ko.dart
       └─ main.dart

 

 

iOS의 경우는 Info.plist에 번역하려는 locale을 추가해야 합니다.

<key>CFBundleLocalizations</key>
<array>
  <string>en</string>
  <string>ko</string>
</array>

 

 

이렇게 기기의 설정된 언어로 다국어 처리하는 방법을 알아보았습니다.

 

 

 

 

[Reference]

software-creator.tistory.com/24

pub.dev/packages/intl/versions/0.16.1

pub.dev/packages/intl_translation

728x90
반응형

댓글