OSDN Git Service

UIカルチャの初期化処理を書き直し
authorKimura Youichi <kim.upsilon@bucyou.net>
Sat, 18 Feb 2017 18:34:59 +0000 (03:34 +0900)
committerKimura Youichi <kim.upsilon@bucyou.net>
Sat, 18 Feb 2017 18:40:10 +0000 (03:40 +0900)
カルチャ名の前方一致で判断していた箇所を、カルチャの階層構造を考慮して判定するように変更

OpenTween.Tests/ExtensionsTest.cs [new file with mode: 0644]
OpenTween.Tests/MyApplicationTest.cs
OpenTween.Tests/OpenTween.Tests.csproj
OpenTween/ApplicationEvents.cs
OpenTween/Extensions.cs
OpenTween/MyCommon.cs

diff --git a/OpenTween.Tests/ExtensionsTest.cs b/OpenTween.Tests/ExtensionsTest.cs
new file mode 100644 (file)
index 0000000..023d948
--- /dev/null
@@ -0,0 +1,59 @@
+// OpenTween - Client of Twitter
+// Copyright (c) 2017 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
+// All rights reserved.
+//
+// This file is part of OpenTween.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. If not, see <http://www.gnu.org/licenses/>, or write to
+// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace OpenTween
+{
+    public class ExtensionsTest
+    {
+        [Theory]
+        [InlineData("ja", "ja-JP", true)]
+        [InlineData("ja", "ja", true)]
+        [InlineData("ja-JP", "ja-JP", true)]
+        [InlineData("ja-JP", "ja", false)]
+        // 4 階層以上の親を持つカルチャ
+        // 参照: https://msdn.microsoft.com/ja-jp/library/dd997383(v=vs.100).aspx#%E6%96%B0%E3%81%97%E3%81%84%E7%89%B9%E5%AE%9A%E3%82%AB%E3%83%AB%E3%83%81%E3%83%A3
+        [InlineData("zh-Hant", "zh-TW", true)]
+        [InlineData("zh-Hant", "zh-CHT", true)]
+        [InlineData("zh-Hant", "zh-Hant", true)]
+        [InlineData("zh-Hant", "zh", false)]
+        public void Contains_Test(string thisCultureStr, string thatCultureStr, bool expected)
+        {
+            var thisCulture = new CultureInfo(thisCultureStr);
+            var thatCulture = new CultureInfo(thatCultureStr);
+            Assert.Equal(expected, thisCulture.Contains(thatCulture));
+        }
+
+        public void Contains_InvariantCultureTest()
+        {
+            // InvariantCulture は全てのカルチャを内包する
+            Assert.True(CultureInfo.InvariantCulture.Contains(new CultureInfo("ja")));
+            Assert.True(CultureInfo.InvariantCulture.Contains(CultureInfo.InvariantCulture));
+        }
+    }
+}
index 0a15706..1b5bcde 100644 (file)
@@ -21,6 +21,7 @@
 
 using System;
 using System.Collections.Generic;
+using System.Globalization;
 using System.Linq;
 using System.Text;
 using Xunit;
@@ -106,5 +107,16 @@ namespace OpenTween
             },
             MyApplication.ParseArguments(args));
         }
+
+        [Theory]
+        [InlineData("ja-JP", "ja-JP")]
+        [InlineData("fr-FR", "en")] // 対応するカルチャが無い場合は en にフォールバックする
+        [InlineData("zh-CN", "zh-CN")] // zh-CHS は zh-CN を内包する
+        [InlineData("zh-TW", "en")] // zh-CHS は zh-TW を内包しない (台湾は繁体字圏)
+        public void GetPreferredCulture_Test(string currentCulture, string expectedCulture)
+        {
+            var actual = MyApplication.GetPreferredCulture(new CultureInfo(currentCulture));
+            Assert.Equal(expectedCulture, actual.Name);
+        }
     }
 }
index 344e021..baffc9e 100644 (file)
@@ -83,6 +83,7 @@
     <Compile Include="Connection\OAuthUtilityTest.cs" />
     <Compile Include="Connection\TwitterApiConnectionTest.cs" />
     <Compile Include="EmojiFormatterTest.cs" />
+    <Compile Include="ExtensionsTest.cs" />
     <Compile Include="HashtagManageTest.cs" />
     <Compile Include="HttpMessageHandlerMock.cs" />
     <Compile Include="IndexedSortedSetTest.cs" />
index e163796..e4842d0 100644 (file)
@@ -43,6 +43,13 @@ namespace OpenTween
 {
     internal class MyApplication
     {
+        public static readonly CultureInfo[] SupportedUICulture = new[]
+        {
+            new CultureInfo("en"), // 先頭のカルチャはフォールバック先として使用される
+            new CultureInfo("ja"),
+            new CultureInfo("zh-CHS"),
+        };
+
         /// <summary>
         /// 起動時に指定されたオプションを取得します
         /// </summary>
@@ -177,46 +184,34 @@ namespace OpenTween
             }
         }
 
-        private static bool IsEqualCurrentCulture(string CultureName)
+        public static void InitCulture()
         {
-            return Thread.CurrentThread.CurrentUICulture.Name.StartsWith(CultureName, StringComparison.Ordinal);
-        }
+            var currentCulture = CultureInfo.CurrentUICulture;
 
-        public static string CultureCode
-        {
-            get
+            var settingCultureStr = SettingManager.Common.Language;
+            if (settingCultureStr != "OS")
             {
-                if (MyCommon.cultureStr == null)
+                try
                 {
-                    MyCommon.cultureStr = SettingManager.Common.Language;
-                    if (MyCommon.cultureStr == "OS")
-                    {
-                        if (!IsEqualCurrentCulture("ja") &&
-                           !IsEqualCurrentCulture("en") &&
-                           !IsEqualCurrentCulture("zh-CN"))
-                        {
-                            MyCommon.cultureStr = "en";
-                        }
-                    }
+                    currentCulture = new CultureInfo(settingCultureStr);
                 }
-                return MyCommon.cultureStr;
+                catch (CultureNotFoundException) { }
             }
+
+            var preferredCulture = GetPreferredCulture(currentCulture);
+            CultureInfo.DefaultThreadCurrentUICulture = preferredCulture;
+            Thread.CurrentThread.CurrentUICulture = preferredCulture;
         }
 
-        public static void InitCulture()
+        /// <summary>
+        /// サポートしているカルチャの中から、指定されたカルチャに対して適切なカルチャを選択して返します
+        /// </summary>
+        public static CultureInfo GetPreferredCulture(CultureInfo culture)
         {
-            try
-            {
-                var culture = CultureInfo.CurrentCulture;
-                if (CultureCode != "OS")
-                    culture = new CultureInfo(CultureCode);
+            if (SupportedUICulture.Any(x => x.Contains(culture)))
+                return culture;
 
-                CultureInfo.DefaultThreadCurrentUICulture = culture;
-                Thread.CurrentThread.CurrentUICulture = culture;
-            }
-            catch (Exception)
-            {
-            }
+            return SupportedUICulture[0];
         }
 
         private static bool SetConfigDirectoryPath()
index 7d36d6a..db95a7b 100644 (file)
@@ -21,6 +21,7 @@
 
 using System;
 using System.Collections.Generic;
+using System.Globalization;
 using System.Linq;
 using System.Text;
 using System.Threading;
@@ -51,5 +52,20 @@ namespace OpenTween
 
         public static UpgradeableReadLockTransaction BeginUpgradeableReadTransaction(this ReaderWriterLockSlim lockObj)
             => new UpgradeableReadLockTransaction(lockObj);
+
+        /// <summary>
+        /// 一方のカルチャがもう一方のカルチャを内包するかを判断します
+        /// </summary>
+        public static bool Contains(this CultureInfo @this, CultureInfo that)
+        {
+            if (@this.Equals(that))
+                return true;
+
+            // InvariantCulture の親カルチャは InvariantCulture 自身であるため、false になったら打ち切る
+            if (!that.Parent.Equals(that))
+                return Contains(@this, that.Parent);
+
+            return false;
+        }
     }
 }
index 5bb0c9e..1baa521 100644 (file)
@@ -56,7 +56,6 @@ namespace OpenTween
     {
         private static readonly object LockObj = new object();
         public static bool _endingFlag;        //終了フラグ
-        public static string cultureStr = null;
         public static string settingPath;
 
         public enum IconSizes