はじめに
こちらは個人開発アプリができるまで by am10 Advent Calendar 2024の 13 日目の記事です。
13 日目はローカライズについてです。
日本語と英語に対応します。
設定ファイル作成
PROJECT > Info > Localizations > + で Japanese を追加します。
New File frome Template ... から Localizable.xcstrings を追加します。
一度ビルドすると下記のような値が自動で設定されます。あとはここにキーと値を設定して View で呼び出すだけです。
キーはこのまま使ってもいいのですが日本語は同じ単語でも英語は違う単語を使いたいという場合もあるのですべての文言にスネークケース(hoge_fuga のようなやつ)でキーを追加します。
英語がわからない場合は ChatGPT に聞きます。
年画面
年画面からローカライズしていきます。
データ取得ボタンなどは下記のように直接キーを指定していきます。
1 |
Button("fetch_button_title") |
ローディングのメッセージなど String 型を渡す必要がある場合は下記のように渡します。
1 |
loadingState = .loading(message: .init(localized: "loading_fetch_message")) |
項目・サブ項目名も下記のようにローカライズします。
1 2 3 4 5 6 7 8 9 10 11 12 |
extension Category { // 表示名 var name: String { switch self { case .food: return .init(localized: "category_food_name") case .entertainment: return .init(localized: "category_entertainment_name") } } } |
エラーのメッセージも同様に下記のようにローカライズします。
1 2 3 4 5 6 7 8 9 10 11 12 |
extension APIError: LocalizedError { /// アラートで画面に表示する用のメッセージ var errorDescription: String? { switch self { case .network: return .init(localized: "api_error_message_network") case .server, .invalidJSON: return .init(localized: "api_error_message_server") } } } |
金額表示は下記のように Text に直接設定してやると 3 桁カンマ区切りになったのですが String にする場合は少し工夫が必要です。
1 |
Text("\(totalPrice)円") |
PriceFormatter.swift を作成し下記のように実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import Foundation struct PriceFormatter { private let formatter = NumberFormatter() /// 金額に3桁おきにカンマをいれる /// - Parameter price: 金額 /// - Returns: 3桁おきにカンマをいれた金額(変換できない場合は0を返す) func format(price: Int) -> String { formatter.numberStyle = .decimal return formatter.string(from: NSNumber(value: price)) ?? "0" } } |
合計金額表示を下記のように修正します。
1 2 3 |
Text(String(format: String(localized: "price_value"), PriceFormatter().format(price: totalPrice))) |
price_value の設定は下記です。
1 2 3 4 |
// 英語 price_value = "%@ yen" // 日本語 price_value = "%@ 円" |
月画面
月画面の対応もほぼ年画面と同じです。少し工夫がいりそうなのが月選択用のピッカーです。
下記のように修正して DateFormatter の monthSymbols を表示するようにします。これでローカライズした各月が表示されます。
1 2 3 4 5 6 7 8 9 |
// 追加 private let monthSymbols: [String] = DateFormatter().monthSymbols Picker("mont_picker_label", selection: $month) { ForEach(months, id: \.self) { // ここ修正 Text(monthSymbols[Int($0)! - 1]) } } |
登録画面
登録画面も同様に対応します。気をつけるのは ReceiptOCRViewController の読み取りボタンくらいだと思います。
下記のようにエラーなどと同じ対応が必要です。
1 |
readButton.setTitle(.init(localized: "ocr_read_button_title"), for: .normal) |
これで画面のローカライズは完了です。
Localizable.xcstrings を確認してみます。
ん?謎の %@(%@)がいます。%@(%@)のキーを選択して右矢印をクリックして使用箇所にとびます。
MonthListView と RegisterView の下記が自動で追加されているようです。
1 |
Text("\(item.category.name)(\(item.category.subName))") |
下記のように修正し自動で追加されないようにします。これで今度こそ完成です!
1 |
Text(verbatim: "\(item.category.name)(\(item.category.subName))") |
アプリ名
次にアプリ名とカメラなどの権限周りのローカライズをします。
New File frome Template ... から InfoPlist.xcstrings を追加します。
TARGETS > General > Identity の Display Name にアプリの英語名を入力します。
一度ビルドすると下記のように自動で値が設定されます。
デフォルト値の英語はここで入力できないので日本語のみ入力し英語は TARGETS > Info から「Privacy - NFC Scan Usage Description」などに入力します。
もう一度ビルドします。
もし State に NEED REVIEW など表示されている場合は右クリックをして Mark as Reviewed で更新していきます。
めんどくさい場合はファイルを右クリックして Open As > Source Code で JSON 形式でファイルを開きます。
option + cmd + F で置換機能を開き上に「"state" : "needs_review",」下に「"state" : "translated",」を入力して All をクリックで置換してしまえば一気にできます。
これでローカライズは完成です!
おわりに
これで言語設定が日本語の場合は日本語表示それ以外の場合は英語表示になりました。
いよいよアプリは完成に近づいてきています。
明日はダークモードに対応します。
コメント