🏂🏼
2021-08-30

【Flutter】Googleスプレッドシートを使って国際化(i18n)対応をする(null safety)

Flutter

Flutterで国際化対応するときに便利なGoogle app scriptを用いたファイル生成を紹介します.

intl_translationパッケージが,null safetyをサポートしなくなりました.

今後は,flutter generateでファイルを生成する必要がありますが,arbを手書きしてくのは辛いのでGoogleスプレッドシートで翻訳情報を管理すると楽になるので管理方法を紹介する

国際化(i18n)対応をする

pubspec.yaml のdependeciesにflutter_localizationsとintlを追加します.同様にflutterのgenerateフラグをtrueにします.

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  intl: ^0.17.0

flutter:
  generate: true


ルートディレクトリに l10n.yamlというファイルを作ります.ここにgenerate先や参照元を指定できます.

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

lib/l10n 以下に*.arb ファイルを配置します.
intl_ja.arb

{
  "@@locale": "ja",
  "helloworld": "ハローワールド"
}

intl_en.arb

{
  "@@locale": "en",
  "helloworld": "helloworld"
}

iOSの場合は,
open ios/Runner.xcworkspace  でworkspaceを開きます.
Localizationsに対応したい言語を追加します.

アプリケーション側の対応

生成されたファイルをimportします.
import 'package:fluttergen/genl10n/app_localizations.dart';
国際化対応したい文字列はAppLocalizations.of(context)!.helloWorld で呼び出す事ができます.
最小構成のサンプルコードは以下のようになります.

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Localizations Sample App',
      localizationsDelegates: [
        AppLocalizations.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: [
        Locale('en', ''),
        Locale('ja', ''),
      ],
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              AppLocalizations.of(context)!.helloworld,
            ),
          ],
        ),
      ),
    );
  }
}


GoogleAppScriptを用いて国際化対応に必要なファイルを生成する

スプレッドシートを作成します.
今回用意したスクリプトでは,4行目から翻訳対象のデータとしています.
また,#をつけることでコメントを書くことが出来るようにしています.ユースケースやスクリーンに対応したコメントをつけると良いと思います.

A列目にFlutterで呼び出しに使うメソッド名,B列目に翻訳文字列に対する説明,C列目以降に文字列を入れるようにしています.

ツールからスクリプトエディタを選択し,myFunctionを実行することでGoogleDriveに*.arb が生成されます.
ファイルをダウンロードし,lib/l10n 以下に配置することで使用することが出来ます.

const col_key = 0
const col_desc = 1
const col_ja = 2
const col_en = 3

const row_data_start = 3

const comment_out_string = '#'

function generateArb(data) {
  const exportHeader = "{\n"
  const exportFooter = "}\n"
  
  const arbSettings = [
    {
      "locale": "ja",
      "file_name": "intl_ja.arb",
      "col": col_ja,
    },
    {
      "locale": "en",
      "file_name": "intl_en.arb",
      "col": col_en,
    },
  ]
    
  arbSettings.forEach(arb => {
    let exportData = ""
    exportData += exportHeader
    
    let locale = `  "@@locale": "${arb['locale']}",\n`
    exportData += locale
    
    data.forEach(function(e, index, array) {
      if (index === array.length - 1){
        exportData += `  "${e[col_key]}": "${e[arb['col']]}"\n`
      } else {
        exportData += `  "${e[col_key]}": "${e[arb['col']]}",\n`
      }
    })
    exportData += exportFooter
    exportDataToDrive(exportData, arb['file_name'])
  })
}

function exportDataToDrive(data, fileName) {
    const blob = Utilities.newBlob(data, MimeType.PLAIN_TEXT, fileName)
    DriveApp.createFile(blob)
}

function myFunction() {
  const sheet = SpreadsheetApp.getActiveSheet()
  const data = sheet.getDataRange().getValues()

  const transData = data.splice(row_data_start, data.length)
  const filtterdTransData = transData.filter(e => e[col_key] !== '').filter(e => e[col_key].slice(0, 1) !== comment_out_string)
  
  generateArb(filtterdTransData)
}


サンプルプロジェクトを用意しました.実際に試してみたい方はぜひ使ってください🎅🏽
https://github.com/kawa1214/flutter-l10n-app-script