前職は世界中で開発したソフトウェアを販売しており、同じWindowsでも日英中韓台独仏伊と8か国くらいの言語版でテストしてたりしました。するとドイツ版で変な挙動をするという報告を受けました。どうも数値がおかしくなるんだそうです。それで当時調べてみました。
値が1000分の1になったりクラッシュしたりする
問題の挙動
前職で開発していたソフトウェアは産業機械関連なので設定値がたくさんあります。例えば距離でメートルの設定はたくさん出てきますし、ミリメートルだとそれなりの桁数になるので、桁区切り文字の「,」を自動で入力するようにしていました。
1,000 mm
こんな感じで保存されます。しかし保存して再度設定画面を開くとドイツ版だと下記のようになってしまうとのこと。
1 mm
なんということでしょう。何が起こっているんだ。日本語や英語では起きないのに…。
原因は国や地域の桁区切り文字設定
桁区切り文字が国や地域によって違う
これが衝撃的だったのですが、実は桁区切り文字が国や地域によって違います。国際規格では小数点にピリオド「.」を使うことになっているようですが、少なくともWindowsは汎用的なOSなので国や地域の慣習を優先して使います。例えばドイツの場合は桁区切り文字がピリオド「.」で小数点が「,」で日本と逆です。
coliss.com
中には桁区切り文字がスペースな国もありますが、Windowsの標準設定はどうなっているんですかね。考えるだけでも恐ろしいです。
コードでは何が起きていたのか
桁区切り文字を追加するとき
例えばWindowsの場合は,Net Frameworkを使って数値に桁区切り文字を付けてString型にすることができます。
string.Format("{0:N0}", value);
これがWindowsの設定によって挙動が変わります。例えば「1000」を渡したとき桁区切り文字が「,」の場合は「1,000」ですし、「.」のときは「1.000」になります。
桁区切り文字を除去するとき
先ほど桁区切り文字を追加した文字列を再び数値に変換してDBなどに保存する場合を考えます。桁区切り文字を含む文字列を数値に素直に変換するメソッドが.Net Frameworkにはないので、簡易的に下記のように書くことが多いのではないかと思います。
int.Parse(valueString.Replace(",", ""));
ここでvalueStringが「1.000」だとクラッシュします。実際はint.TryParseを使ってエラーハンドリングで0とか無害な数値になるかもしれませんが、いずれにせよ正常には動きませんね。ちなみに最初に「1,000mm」が「1mm」になった理由はドイツ版で問題が起きた環境を開発陣の日本版環境で検証したからとかそんな感じだった気がします。もう環境が混ざるとカオスです。
どのように対策すれば良いのか
運用で回避してしまう
前職は割と規模が大きくソフトウェアの改修コストが大変なことになってしまうので、各国でも桁区切り文字に「,」を使うように運用で回避してもらうことにしました。Windowsの設定で桁区切り文字を変えることができます。
www.wannko.net
ちゃんと対応するには?
やってないので調べてないのですが、例えばここら辺とか使って何とかできそうな気もします。
docs.microsoft.com
これってAndroidやiOSだとどうなんでしょうね。