3流プログラマのメモ書き

元開発職→社内SE→派遣で営業支援の三流プログラマのIT技術メモ書き。 このメモが忘れっぽい自分とググってきた技術者の役に立ってくれれば幸いです。(jehupc.exblog.jpから移転中)

(.NET)多言語対応化

要件

Windows Formアプリで多言語対応したい。 ・どの言語にするかは、App.config にカルチャコード(jaとかes)とかを指定する。 (今回、英語で作ったアプリを日本語化する例となってます。)

Formの多言語化

Form の[Localizable]プロパティを True にします。 そして、[Language]プロパティを (規定値) から多言語対象言語に変更します。
この際、[Language]プロパティの言語選択プルダウンを見ると、 [日本語] だけでなく [日本語(日本)] というようにカッコで地域名が書いたものがあります。言語名だけのものは、ニュートラル・カルチャ と呼び、地域・国名が入ってるものは特定のカルチャ(固有カルチャ)と呼ばれるようです。適用順序としては、ニュートラル・カルチャ → 特定のカルチャ となるようです。今回はニュートラル・カルチャのみ使用することにしました。

次に、フォーム上の文言を多言語対象言語に修正します。
そうすると、以下のようにFormに規定値のほかに対象言語用のリソースファイルが作成されます。

Form以外のリソース(ダイアログボックスに表示するメッセージなど)の多言語化

メッセージなどの文字列をリソースファイルで定義していない(ソース埋め込み等)の場合は、Properties の下に、新たに規定言語用のリソースファイルファイルを作成し、そのリソースファイルにメッセージの内容を定義、それを参照するようソースコードを修正します。

そして規定言語用のリソースファイルをコピー → Properties配下でペーストし、末尾に多言語対象言語のカルチャコードを加えます。
追加した多言語対象言語のリソースファイルの内容を、対応言語の内容に変更します。

以下は日本語用のリソースファイルを追加した場合の例です。

各言語のカルチャコードは、[MS-LCID]: Appendix A: Product Behavior | Microsoft Learn の Language tag で知ることができます。

ちなみに、リソースファイルの文字列を参照するには以下のようにします。(HOGEという名前で定義)

MessageBox.Show( Properties.Resources.MSG_HOGE );

余談ですが、リソースファイル化すると以下のような文字列補完式は使えません。

string str = "piyo" ;
MessageBox.Show( $"hoge {str}" );

代わりに以下のようにString.Format を使うことで対応することができます。
リソースファイルの内容。

hoge {0}
string str = "piyo" ;
MessageBox.Show( String.Format( Properties.Resources.MSG_HOGE , str);

利用する言語を指定する方法

デフォルトでアプリを実行するユーザー環境によって、自動的に対応するカルチャ(言語)のリソースが使用されるようです。 でも、コードでどのカルチャか指定することも可能です。

以下は、App.config に指定されたカルチャ使用するにした例です。

public MainForm()
{
    //言語設定
    String language = Properties.Settings.Default.Language;
    _culture = new CultureInfo(language);
    Thread.CurrentThread.CurrentUICulture = _culture;
    InitializeComponent();
}

Windowsフォームなどのリソース関連の場合は、Thread.CurrentThread.CurrentUICulture プロパティで指定できます。

参考:
多言語対応(C#、Windows Forms編) | tocsworld
【Windows Forms】C#で多言語化対応をしてみる | ReMIXのブログ
Windowsフォームを多言語対応にするには?:.NET TIPS - @IT
[C#] Windows Formアプリの多言語対応 | OsadaSoft

(Android,Java)RoomでDBスキーマが変わった場合の対応(DBファイルは別途用意)

Roomを使っているAndroidアプリで、DBスキーマの変更(列の型変更)の必要が発生しました。その際、マイグレーションをしないと実行時にエラーとなってしまいます。 その際の対応メモです。
言語はJavaです。
なお、DBファイルは例外的な方法ですが、アプリ内でスキーマを変更せず、PC上で変更してAndroidバイス側に持ってくる仕様としています。
(DBファイル自体もアプリ固有領域ではなく、外部ストレージ= Context#getExternalFilesDir に配置)

1.DBの変更

上記に書いたように、今回DBファイルはPC側から持ってくるという仕様としています。
それでPC側で、DB Browser for SQLite 等を使ってスキーマを変更します。

今回のDBスキーマの変更は、列の型の変更です。
余談ですが、SQLiteでの型変更も少し厄介で、以下を参考にさせてもらいました。
SQLite 備忘録 - SQLite3 カラムの型を変更するを参照。

2.エンティティやDAOの変更

変更になったスキーマの情報をエンティティ側にも反映します。
必要であればDAOも修正します。

3.Databaseクラスのアノテーションでバージョン番号記載

RoomDatabaseを継承したクラスの@Databaseアノテーションで、versionの値をインクリメントします。

@Database(entities = {Test.class},
    version = 2,exportSchema = true)
public abstract class AppDatabase  extends RoomDatabase {
    public abstract TestoDao testDao();
}

上記では version が1だったのを2にしました。

4.マイグレーションコードを記載し、DB作成時にaddMigrationsメソッドを追加

マイグレーションのためのSQLを記載するのですが、今回は上述の通りDBファイルをPC側で変更して差し替えます。
とはいえ、マイグレーションコードを書かないとRoomがエラーとなるため、メソッドは用意するものの、実装は空とします。
そして、Room.databaseBuilderで、マイグレーションコードを呼び出すようにします。z

//マイグレーションコード
final Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        //通常は以下にマイグレーションのSQLを記載するが、今回は空実装。
        //database.execSQL("CREATE TABLE ...");
    }
};

//Room生成時に、上記マイグレーションコードをのメソッドを呼び出すようにする。
Room.databaseBuilder(context,AppDatabase.class, DBPATH)
.setJournalMode(RoomDatabase.JournalMode.TRUNCATE) //SQLiteジャーナルモード:truncateモード。WALだとジャーナルファイルが残るため。
.addMigrations(MIGRATION_1_2)  //ここでマイグレーションコードを実行
.build();

参考:
RoomでMigration #Android - Qiita
Roomのマイグレーションまとめ. Roomのマイグレーションについてまとめておきます。 | by Kenji Abe | Medium
Room データベースを移行する | Android Developers
【Androidアプリ開発】Room利用時のエラーと対処方法 | プログラミング・開発の備忘録
roomをmigrationする
Roomのマイグレーション | KINTO Tech Blog | キントテックブログ