App Store Connect で多言語対応するときは、GUIで国ごとにタイトルや説明文、プロモーションテキストを書かなければならず、けっこうな手間がかかります。
Expo のプロジェクトでは、 store.config.json
を使うことで、これらの入力をかなり省力化できます。 store.config.json
をプロジェクトのルートに配置しましょう。
touch store.config.json
公式のサンプルでは以下のようになっています。
{
"configVersion": 0,
"apple": {
"info": {
"en-US": {
"title": "Awesome App",
"subtitle": "Your self-made awesome app",
"description": "The most awesome app you've ever seen",
"keywords": ["awesome", "app"],
"marketingUrl": "https://example.com/en/promo",
"supportUrl": "https://example.com/en/support",
"privacyPolicyUrl": "https://example.com/en/privacy"
}
}
}
}
多言語化対応
まずは多言語化対応を行います。上の例だと en-US
しかないので、Apple info languages を見ながら必要な言語を追加していきます。 "en-US":
と同じ階層に言語設定をコピペで追加していけばOKです。
アプリの説明文は日本語で書いて、その他の言語への翻訳は機械翻訳よりも GPT-4 を使う方がいい感じにしてくれます。
以下のようなJSONで、アプリの説明文とキーワードを書いています。
```
"ja": {
"description": "習慣サプリは習慣づけを応援するアプリです。\\n習慣にしたいタスクについて、どれだけ時間を投入できたかを記録できます。\\n一つ一つのタスクはストップウォッチで時間を測ることができます。その時間を記録して、振り返ることができるので、モチベーションが維持しやすくなっています。",
"keywords": ["habit", "todo", "note", "stopwatch", "成長", "習慣", "成功", "繰り返し", "勉強を習慣にする", "毎日勉強", "勉強時間の記録"],
}
```
この説明文をを多言語化したいです。
英語、ドイツ語、スペイン語、韓国語が対象です。
上記の日本語での説明を踏まえて、それぞれの言語で、わかりやすい文章で説明文を書いてください。また、キーワードの配列も作成してください。
出力はそれぞれの言語で json の形でお願いします。
GPT-4 か DeepL を使って、いい感じに翻訳してみてください。
カテゴリを選択する
Apple categories を見ながら、自分のアプリケーションのカテゴリを設定します。二重配列のうち、前半はプライマリカテゴリで、後半はサブカテゴリです。
{
"configVersion": 0,
"apple": {
"categories": ["UTILITIES", "LIFESTYLE"],
}
}
年齢制限の設定
Apple advisory を見ながら、年齢制限の設定を行います。ギャンブル的なコンテンツがあるかどうか、などを設定します。1度手動で App Store Connect で登録した経験がないとイメージが湧きづらいかもしれません。 apple.advisory
に情報を配置します。
{
"configVersion": 0,
"apple": {
"advisory": {
"alcoholTobaccoOrDrugUseOrReferences": "NONE",
"contests": "NONE",
"gamblingSimulated": "NONE",
"horrorOrFearThemes": "NONE",
"matureOrSuggestiveThemes": "NONE",
"medicalOrTreatmentInformation": "NONE",
"profanityOrCrudeHumor": "NONE",
"sexualContentGraphicAndNudity": "NONE",
"sexualContentOrNudity": "NONE",
"violenceCartoonOrFantasy": "NONE",
"violenceRealistic": "NONE",
"violenceRealisticProlongedGraphicOrSadistic": "NONE",
"gambling": false,
"unrestrictedWebAccess": false,
"kidsAgeBand": null,
"seventeenPlus": false
}
}
}
自動リリースの設定
手動リリース化自動リリースかを設定します。審査終了後に自動でリリースして良ければ、 "automaticRelease": true
を指定します。
完成形のひながたは以下のとおりです。
{
"configVersion": 1,
"apple": {
"advisory": {
"alcoholTobaccoOrDrugUseOrReferences": "NONE",
"contests": "NONE",
"gamblingSimulated": "NONE",
"horrorOrFearThemes": "NONE",
"matureOrSuggestiveThemes": "NONE",
"medicalOrTreatmentInformation": "NONE",
"profanityOrCrudeHumor": "NONE",
"sexualContentGraphicAndNudity": "NONE",
"sexualContentOrNudity": "NONE",
"violenceCartoonOrFantasy": "NONE",
"violenceRealistic": "NONE",
"violenceRealisticProlongedGraphicOrSadistic": "NONE",
"gambling": false,
"unrestrictedWebAccess": false,
"kidsAgeBand": null,
"seventeenPlus": false
},
"categories": [["LIFESTYLE"], "UTILITIES"],
"release": {
"automaticRelease": true
},
"review": {
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com",
"phone": "+1 123 456 7890",
"demoUsername": "john",
"demoPassword": "applereview",
"demoRequired": false,
"notes": "This is an example app primarily used for educational purposes."
},
"info": {
"en-US": {
"title": "Awesome App",
"subtitle": "Your self-made awesome app",
"description": "The most awesome app you've ever seen",
"keywords": ["awesome", "app"],
"releaseNotes": "",
"promoText": "",
"marketingUrl": "https://example.com/en/promo",
"supportUrl": "https://example.com/en/support",
"privacyPolicyUrl": "https://example.com/en/privacy"
},
"en-AU": {
"title": "Awesome App",
"subtitle": "Your self-made awesome app",
"description": "The most awesome app you've ever seen",
"keywords": ["awesome", "app"],
"marketingUrl": "https://example.com/en/promo",
"supportUrl": "https://example.com/en/support",
"privacyPolicyUrl": "https://example.com/en/privacy"
},
"en-CA": {
"title": "Awesome App",
"subtitle": "Your self-made awesome app",
"description": "The most awesome app you've ever seen",
"keywords": ["awesome", "app"],
"marketingUrl": "https://example.com/en/promo",
"supportUrl": "https://example.com/en/support",
"privacyPolicyUrl": "https://example.com/en/privacy"
},
"en-GB": {
"title": "Awesome App",
"subtitle": "Your self-made awesome app",
"description": "The most awesome app you've ever seen",
"keywords": ["awesome", "app"],
"marketingUrl": "https://example.com/en/promo",
"supportUrl": "https://example.com/en/support",
"privacyPolicyUrl": "https://example.com/en/privacy"
},
"ja": {
"title": "Awesome App",
"subtitle": "Your self-made awesome app",
"description": "The most awesome app you've ever seen",
"keywords": ["awesome", "app"],
"marketingUrl": "https://example.com/en/promo",
"supportUrl": "https://example.com/en/support",
"privacyPolicyUrl": "https://example.com/en/privacy"
},
"es-MX": {
"title": "Awesome App",
"subtitle": "Your self-made awesome app",
"description": "The most awesome app you've ever seen",
"keywords": ["awesome", "app"],
"marketingUrl": "https://example.com/en/promo",
"supportUrl": "https://example.com/en/support",
"privacyPolicyUrl": "https://example.com/en/privacy"
},
"es-ES": {
"title": "Awesome App",
"subtitle": "Your self-made awesome app",
"description": "The most awesome app you've ever seen",
"keywords": ["awesome", "app"],
"marketingUrl": "https://example.com/en/promo",
"supportUrl": "https://example.com/en/support",
"privacyPolicyUrl": "https://example.com/en/privacy"
},
"ko": {
"title": "Awesome App",
"subtitle": "Your self-made awesome app",
"description": "The most awesome app you've ever seen",
"keywords": ["awesome", "app"],
"marketingUrl": "https://example.com/en/promo",
"supportUrl": "https://example.com/en/support",
"privacyPolicyUrl": "https://example.com/en/privacy"
}
}
}
}
アプリの表示名を場所ごとに切り替える
app.json
の expo
直下の場所、つまり ios
と同じ階層に locales
を配置します。
{
"expo": {
"name": "Habit Motivator",
"ios": {},
"locales": {
"ja": "./languages/ja.json",
"en-US": "./languages/en-US.json",
"en-GB": "./languages/en-GB.json",
"en-CA": "./languages/en-CA.json",
"en-AU": "./languages/en-AU.json",
"es-MX": "./languages/es-MX.json",
"es-ES": "./languages/es-ES.json",
"de-DE": "./languages/de-DE.json",
"ko": "./languages/ko.json"
},
}
}
mkdir languages
languages
以下に移動して、以下のコマンドを打ちます。
cd languages
touch {en-GB,en-CA,en-AU,en-US,ja,es-MX,es-ES,de-DE,ko,zh-Hans,zh-Hant,ru}.json
languages/ja.json
には以下のように書きます。
{
"CFBundleDisplayName": "習慣サプリ",
"NSContactsUsageDescription": "習慣づけの成功を全力で応援するアプリ"
}
メタデータは以下のコマンドでプッシュできます。ただ、これは後述する eas submit
の後で実行してください。
eas metadata:push
ちなみに、アプリ名については機械翻訳するよりも ChatGPTを使った方がそれっぽくなります。
日本語で、以下のような名前のアプリを作っています。以下のファイルは ja.json です。
```
{
"CFBundleDisplayName": "習慣サプリ",
"NSContactsUsageDescription": "習慣づけの成功を全力で応援するアプリ"
}
```
このアプリを多言語化したいです。
英語、ドイツ語、スペイン語、韓国語で、それぞれ日本語でのイメージに適した良いアプリ名を提案してくれませんか?
それぞれの言語で、できるだけ短く、魅力的な名前で提案してもらいたいです。
出力はそれぞれの言語で json の形でお願いします。
App Store Connect にビルドしたファイルをアップロードする
以下のコマンドを実行します。
eas build:configure
eas build
# eas build を実行すると、 eas.json ファイルができるので、 store.config.json へのパスを設定する(下の項目を参照してください)
eas submit
App Store Connect に多言語情報をアップロードする
eas.json
の "submit"
を編集して、 metadataPath
に store.config.json
を指定します。
"submit": {
"production": {
"ios": {
"metadataPath": "./store.config.json"
}
}
}
以下のコマンドを実行すると、メタデータが App Store Connect に push されます。
eas metadata:push
言語コードの対応
それぞれのファイルの言語コードの対応を表にします。
言語 | app.json の locales | store.config.jsonのinfo | i18n | GOOGLETRANSLATE |
日本語 | ja | ja | ja | ja |
英語(アメリカ) | en | en-US | en | en |
英語(オーストラリア) | en | en-AU | en | en |
英語(カナダ) | en | en-CA | en | en |
英語(イギリス) | en | en-GB | en | en |
スペイン語(メキシコ) | es | es-MX | es | es |
スペイン語(スペイン) | es | es-ES | es | es |
ドイツ語 | de | de-DE | de | de |
韓国語 | ko | ko | ko | ko |
ISO 639-1 の 言語コード(2文字で表現する決まりがあるらしい)Codes arranged alphabetically by alpha-3/ISO 639-2 Codeapp.json
の "locales"
は 2文字にします。
Google Sheets の GOOGLETRANSLATE
関数の言語コード 言語サポート
まとめて翻訳するために Google Sheets の関数を使います。
翻訳するときは、いちいち DeepL にコピペするのは面倒なので、Google Sheets の関数 =GOOGLETRANSLATE($C3, "ja", "es")
を使って、表計算シートでまとめて翻訳するのが。
エラー対応の記録
eas submit で already been used on a different account が出た場合
App name "tabmemo" has already been used on a different account. If you have trademark rights to this name and would like it released for your use, submit a claim to Apple.
Visit https://appstoreconnect.apple.com and resolve any warnings, then try again.
Submission failed
app.json
の name
と slug
を変更します。 name
は世界で一意でなければいけないので、誰かと被っていたら eas submit
できません。
ただ、単純に slug
を書き換えると、以下のようなエラーが出ます。
Project config: Slug for project identified by "extra.eas.projectId" (xxx) does not match the "slug" field (xxx). Learn more: https://expo.fyi/eas-project-id
app.json
の下の方に extra
ができています。
"extra": {
"eas": {
"projectId": "e4f13461-3cd9-4b0b-8cb5-2e5657ae4bab"
}
}
これは eas build
で、 ? Would you like to automatically create an EAS project for xxx?
と聞かれたときに自動で作成されるものです。
slug
が projectId
を紐付けられているため、 slug
を変更したときは、一度 extra
を削除して、再度 eas build
しなければなりません。