A writing system implementation based on the Palaso writing system library.
Inheritance: WritingSystemDefinition, IWritingSystem
Beispiel #1
0
        /// <summary>
        /// Persists all modified writing systems.
        /// </summary>
        public void Save()
        {
            lock (m_syncRoot)
            {
                DateTime now = DateTime.UtcNow;
                foreach (PalasoWritingSystem ws in m_localStore.AllWritingSystems)
                {
                    if (ws.Modified || ws.DateModified.Ticks == 0)
                    {
                        ws.DateModified = now;
                    }

                    if (ws.MarkedForDeletion)
                    {
                        m_handleWss.Remove(ws.Handle);
                        if (m_userWritingSystem == ws)
                        {
                            m_userWritingSystem = null;
                        }
                    }
                }
                m_localStore.Save();
                Settings.Default.LocalKeyboards = UnionSettingsKeyboardsWithLocalStore();
                Settings.Default.Save();
            }
        }
		void VerifyComponents(PalasoWritingSystem ws, string lang, string script, string region, string variant, string id)
		{
			Assert.That(ws.Language, Is.EqualTo(lang));
			Assert.That(ws.Script, Is.EqualTo(script));
			Assert.That(ws.Region, Is.EqualTo(region));
			Assert.That(ws.Variant, Is.EqualTo(variant));
			Assert.That(ws.Id, Is.EqualTo(id));
		}
Beispiel #3
0
 void VerifyComponents(PalasoWritingSystem ws, string lang, string script, string region, string variant, string id)
 {
     Assert.That(ws.Language, Is.EqualTo(lang));
     Assert.That(ws.Script, Is.EqualTo(script));
     Assert.That(ws.Region, Is.EqualTo(region));
     Assert.That(ws.Variant, Is.EqualTo(variant));
     Assert.That(ws.Id, Is.EqualTo(id));
 }
Beispiel #4
0
        public void LocalKeyboardsUnionLocalStore()
        {
            // Populate Settings.Default.LocalKeyboards
            Settings.Default.LocalKeyboards = "<keyboards>"
                                              + "<keyboard ws=\"en\" layout=\"US\" locale=\"en-US\" />"
                                              + "<keyboard ws=\"zh-CN-pinyin\" layout=\"US\" locale=\"en-US\" />"
                                              + "<keyboard ws=\"zh-CN\" layout=\"Chinese (Simplified) - US Keyboard\" locale=\"zh-CN\" />"
                                              + "</keyboards>";

            // Set up a local store with one conflicting and one additional keyboard
            var localStore = new LocalFileWritingSystemStore(PrepareTempStore("Store"));
            var ws         = new PalasoWritingSystem
            {
                LanguageSubtag = new LanguageSubtag("en", "en", false, null),
                LocalKeyboard  = Keyboard.Controller.CreateKeyboardDefinition("United States-Dvorak", "en-UK")
            };

            localStore.Set(ws);
            ws = new PalasoWritingSystem
            {
                LanguageSubtag = new LanguageSubtag("ko", "ko", false, null),
                LocalKeyboard  = Keyboard.Controller.CreateKeyboardDefinition("US", "ta-IN")
            };
            localStore.Set(ws);
            var wsm = new TestPalasoWritingSystemManager(localStore);

            // SUT
            var resultXml = wsm.TestUnionSettingsKeyboardsWithLocalStore();

            // Parse resulting string into XElements
            var root             = XElement.Parse(resultXml);
            var keyboardSettings = new Dictionary <string, XElement>();

            foreach (var kbd in root.Elements("keyboard"))
            {
                keyboardSettings[kbd.Attribute("ws").Value] = kbd;
            }

            Assert.AreEqual(4, keyboardSettings.Count, "Incorrect number of keyboards in Union");
            // the same
            Assert.AreEqual("US", keyboardSettings["zh-CN-pinyin"].Attribute("layout").Value, "Pinyin keyboard layout should not have changed");
            Assert.AreEqual("en-US", keyboardSettings["zh-CN-pinyin"].Attribute("locale").Value, "Pinyin keyboard locale should not have changed");
            Assert.AreEqual("Chinese (Simplified) - US Keyboard", keyboardSettings["zh-CN"].Attribute("layout").Value, "Chinese keyboard layout should not have changed");
            Assert.AreEqual("zh-CN", keyboardSettings["zh-CN"].Attribute("locale").Value, "Chinese keyboard locale should not have changed");
            // new or changed
            Assert.AreEqual("United States-Dvorak", keyboardSettings["en"].Attribute("layout").Value, "English keyboard layout should have changed");
            Assert.AreEqual("en-UK", keyboardSettings["en"].Attribute("locale").Value, "English keyboard locale should have changed");
            Assert.AreEqual("US", keyboardSettings["ko"].Attribute("layout").Value, "Korean keyboard layout should have been created");
            Assert.AreEqual("ta-IN", keyboardSettings["ko"].Attribute("locale").Value, "Korean keyboard locale should have been created");
        }
		private PalasoWritingSystem(PalasoWritingSystem ws)
			: base(ws)
		{
			m_defaultFontFeatures = ws.m_defaultFontFeatures;
			m_validChars = ws.m_validChars;
			m_matchedPairs = ws.m_matchedPairs;
			m_punctuationPatterns = ws.m_punctuationPatterns;
			m_quotationMarks = ws.m_quotationMarks;
			m_lcid = ws.m_lcid;
			m_regionName = ws.m_regionName;
			m_scriptName = ws.m_scriptName;
			m_variantName = ws.m_variantName;
			m_legacyMapping = ws.m_legacyMapping;
			m_isGraphiteEnabled = ws.m_isGraphiteEnabled;
		}
Beispiel #6
0
 private PalasoWritingSystem(PalasoWritingSystem ws)
     : base(ws)
 {
     m_defaultFontFeatures = ws.m_defaultFontFeatures;
     m_validChars          = ws.m_validChars;
     m_matchedPairs        = ws.m_matchedPairs;
     m_punctuationPatterns = ws.m_punctuationPatterns;
     m_quotationMarks      = ws.m_quotationMarks;
     m_lcid              = ws.m_lcid;
     m_regionName        = ws.m_regionName;
     m_scriptName        = ws.m_scriptName;
     m_variantName       = ws.m_variantName;
     m_legacyMapping     = ws.m_legacyMapping;
     m_isGraphiteEnabled = ws.m_isGraphiteEnabled;
 }
		void VerifySubtagCodes(PalasoWritingSystem ws, string langCode, string scriptCode, string regionCode, string variantCode, string id)
		{
			Assert.That(ws.LanguageSubtag.Code, Is.EqualTo(langCode));
			if (scriptCode == null)
				Assert.That(ws.ScriptSubtag, Is.Null);
			else
				Assert.That(ws.ScriptSubtag.Code, Is.EqualTo(scriptCode));
			if (regionCode == null)
				Assert.That(ws.RegionSubtag, Is.Null);
			else
				Assert.That(ws.RegionSubtag.Code, Is.EqualTo(regionCode));
			if (variantCode == null)
				Assert.That(ws.VariantSubtag, Is.Null);
			else
				Assert.That(ws.VariantSubtag.Code, Is.EqualTo(variantCode));

			// Now check that we can get the same tags by parsing the ID.

			LanguageSubtag languageSubtag;
			ScriptSubtag scriptSubtag;
			RegionSubtag regionSubtag;
			VariantSubtag variantSubtag;
			LangTagUtils.GetSubtags(id, out languageSubtag, out scriptSubtag, out regionSubtag, out variantSubtag);
			Assert.That(languageSubtag.Code, Is.EqualTo(langCode));
			if (scriptCode == null)
				Assert.That(scriptSubtag, Is.Null);
			else
				Assert.That(scriptSubtag.Code, Is.EqualTo(scriptCode));
			if (regionCode == null)
				Assert.That(regionSubtag, Is.Null);
			else
				Assert.That(regionSubtag.Code, Is.EqualTo(regionCode));
			if (variantCode == null)
				Assert.That(variantSubtag, Is.Null);
			else
				Assert.That(variantSubtag.Code, Is.EqualTo(variantCode));
		}
		public void LanguageAndVariantTags()
		{
			// A new writing system has a Language tag of qaa. This is also its language tag. The others are null.
			var ws = new PalasoWritingSystem();
			VerifySubtagCodes(ws, "qaa", null, null, null, "qaa");
			VerifyComponents(ws, "qaa", "", "", "", "qaa");

			ws.LanguageSubtag = LangTagUtils.GetLanguageSubtag("en");
			VerifySubtagCodes(ws, "en", null, null, null, "en");
			VerifyComponents(ws, "en", "", "", "", "en");
			Assert.That(ws.LanguageName, Is.EqualTo("English"));

			ws.LanguageSubtag = new LanguageSubtag("kal", "Kalaba", true, "");
			Assert.That(ws.LanguageName, Is.EqualTo("Kalaba"));
			VerifySubtagCodes(ws, "kal", null, null, null, "qaa-x-kal");
			VerifyComponents(ws, "qaa", "", "", "x-kal", "qaa-x-kal");
			Assert.That(ws.LanguageSubtag.Name, Is.EqualTo("Kalaba"));

			// This is a region code that is valid, so we don't store it in the private-use area of our code.
			ws.RegionSubtag = LangTagUtils.GetRegionSubtag("QN");
			VerifySubtagCodes(ws, "kal", null, "QN", null, "qaa-QN-x-kal");
			VerifyComponents(ws, "qaa", "", "QN", "x-kal", "qaa-QN-x-kal");

			// This is a standard region (Norway).
			ws.RegionSubtag = LangTagUtils.GetRegionSubtag("NO");
			VerifySubtagCodes(ws, "kal", null, "NO", null, "qaa-NO-x-kal");
			VerifyComponents(ws, "qaa", "", "NO", "x-kal", "qaa-NO-x-kal");

			// A private region
			ws.RegionSubtag = LangTagUtils.GetRegionSubtag("ZD");
			VerifySubtagCodes(ws, "kal", null, "ZD", null, "qaa-QM-x-kal-ZD");
			VerifyComponents(ws, "qaa", "", "QM", "x-kal-ZD", "qaa-QM-x-kal-ZD");

			// Add a private script
			ws.ScriptSubtag = LangTagUtils.GetScriptSubtag("Zfdr");
			VerifySubtagCodes(ws, "kal", "Zfdr", "ZD", null, "qaa-Qaaa-QM-x-kal-Zfdr-ZD");
			VerifyComponents(ws, "qaa", "Qaaa", "QM", "x-kal-Zfdr-ZD", "qaa-Qaaa-QM-x-kal-Zfdr-ZD");

			// Change it to a standard one
			ws.ScriptSubtag = LangTagUtils.GetScriptSubtag("Phnx");
			VerifySubtagCodes(ws, "kal", "Phnx", "ZD", null, "qaa-Phnx-QM-x-kal-ZD");
			VerifyComponents(ws, "qaa", "Phnx", "QM", "x-kal-ZD", "qaa-Phnx-QM-x-kal-ZD");

			// To the standard private-use marker
			ws.ScriptSubtag = LangTagUtils.GetScriptSubtag("Qaaa");
			VerifySubtagCodes(ws, "kal", "Qaaa", "ZD", null, "qaa-Qaaa-QM-x-kal-Qaaa-ZD");
			VerifyComponents(ws, "qaa", "Qaaa", "QM", "x-kal-Qaaa-ZD", "qaa-Qaaa-QM-x-kal-Qaaa-ZD");


			// Back to the special one
			ws.ScriptSubtag = LangTagUtils.GetScriptSubtag("Zfdr");
			VerifySubtagCodes(ws, "kal", "Zfdr", "ZD", null, "qaa-Qaaa-QM-x-kal-Zfdr-ZD");
			VerifyComponents(ws, "qaa", "Qaaa", "QM", "x-kal-Zfdr-ZD", "qaa-Qaaa-QM-x-kal-Zfdr-ZD");

			// Add a standard variant
			ws.VariantSubtag = LangTagUtils.GetVariantSubtag("fonipa");
			VerifySubtagCodes(ws, "kal", "Zfdr", "ZD", "fonipa", "qaa-Qaaa-QM-fonipa-x-kal-Zfdr-ZD");
			VerifyComponents(ws, "qaa", "Qaaa", "QM", "fonipa-x-kal-Zfdr-ZD", "qaa-Qaaa-QM-fonipa-x-kal-Zfdr-ZD");

			// Change it to a combination one
			ws.VariantSubtag = LangTagUtils.GetVariantSubtag("fonipa-x-etic");
			VerifySubtagCodes(ws, "kal", "Zfdr", "ZD", "fonipa-x-etic", "qaa-Qaaa-QM-fonipa-x-kal-Zfdr-ZD-etic");
			VerifyComponents(ws, "qaa", "Qaaa", "QM", "fonipa-x-kal-Zfdr-ZD-etic", "qaa-Qaaa-QM-fonipa-x-kal-Zfdr-ZD-etic");

			// Back to no variant.
			ws.VariantSubtag = null;
			VerifySubtagCodes(ws, "kal", "Zfdr", "ZD", null, "qaa-Qaaa-QM-x-kal-Zfdr-ZD");
			VerifyComponents(ws, "qaa", "Qaaa", "QM", "x-kal-Zfdr-ZD", "qaa-Qaaa-QM-x-kal-Zfdr-ZD");

			// Try a double combination
			ws.VariantSubtag = LangTagUtils.GetVariantSubtag("fonipa-1996-x-etic-emic");
			VerifySubtagCodes(ws, "kal", "Zfdr", "ZD", "fonipa-1996-x-etic-emic", "qaa-Qaaa-QM-fonipa-1996-x-kal-Zfdr-ZD-etic-emic");
			VerifyComponents(ws, "qaa", "Qaaa", "QM", "fonipa-1996-x-kal-Zfdr-ZD-etic-emic", "qaa-Qaaa-QM-fonipa-1996-x-kal-Zfdr-ZD-etic-emic");

			// Drop a piece out of each
			ws.VariantSubtag = LangTagUtils.GetVariantSubtag("fonipa-x-etic");
			VerifySubtagCodes(ws, "kal", "Zfdr", "ZD", "fonipa-x-etic", "qaa-Qaaa-QM-fonipa-x-kal-Zfdr-ZD-etic");
			VerifyComponents(ws, "qaa", "Qaaa", "QM", "fonipa-x-kal-Zfdr-ZD-etic", "qaa-Qaaa-QM-fonipa-x-kal-Zfdr-ZD-etic");

			// Soemthing totally unknown
			ws.VariantSubtag = LangTagUtils.GetVariantSubtag("fonipa-x-blah");
			VerifySubtagCodes(ws, "kal", "Zfdr", "ZD", "fonipa-x-blah", "qaa-Qaaa-QM-fonipa-x-kal-Zfdr-ZD-blah");
			VerifyComponents(ws, "qaa", "Qaaa", "QM", "fonipa-x-kal-Zfdr-ZD-blah", "qaa-Qaaa-QM-fonipa-x-kal-Zfdr-ZD-blah");

			// Drop just the standard part
			ws.VariantSubtag = LangTagUtils.GetVariantSubtag("x-blah");
			VerifySubtagCodes(ws, "kal", "Zfdr", "ZD", "x-blah", "qaa-Qaaa-QM-x-kal-Zfdr-ZD-blah");
			VerifyComponents(ws, "qaa", "Qaaa", "QM", "x-kal-Zfdr-ZD-blah", "qaa-Qaaa-QM-x-kal-Zfdr-ZD-blah");

			// No longer a custom language
			ws.LanguageSubtag = LangTagUtils.GetLanguageSubtag("en");
			VerifySubtagCodes(ws, "en", "Zfdr", "ZD", "x-blah", "en-Qaaa-QM-x-Zfdr-ZD-blah");
			VerifyComponents(ws, "en", "Qaaa", "QM", "x-Zfdr-ZD-blah", "en-Qaaa-QM-x-Zfdr-ZD-blah");

			// No longer a custom script
			ws.ScriptSubtag = null;
			VerifySubtagCodes(ws, "en", null, "ZD", "x-blah", "en-QM-x-ZD-blah");
			VerifyComponents(ws, "en", "", "QM", "x-ZD-blah", "en-QM-x-ZD-blah");

			// No longer a custom region
			ws.RegionSubtag = null;
			VerifySubtagCodes(ws, "en", null, null, "x-blah", "en-x-blah");
			VerifyComponents(ws, "en", "", "", "x-blah", "en-x-blah");

			// No more variant
			ws.VariantSubtag = null;
			VerifySubtagCodes(ws, "en", null, null, null, "en");
			VerifyComponents(ws, "en", "", "", "", "en");
		}
Beispiel #9
0
        void VerifySubtagCodes(PalasoWritingSystem ws, string langCode, string scriptCode, string regionCode, string variantCode, string id)
        {
            Assert.That(ws.LanguageSubtag.Code, Is.EqualTo(langCode));
            if (scriptCode == null)
            {
                Assert.That(ws.ScriptSubtag, Is.Null);
            }
            else
            {
                Assert.That(ws.ScriptSubtag.Code, Is.EqualTo(scriptCode));
            }
            if (regionCode == null)
            {
                Assert.That(ws.RegionSubtag, Is.Null);
            }
            else
            {
                Assert.That(ws.RegionSubtag.Code, Is.EqualTo(regionCode));
            }
            if (variantCode == null)
            {
                Assert.That(ws.VariantSubtag, Is.Null);
            }
            else
            {
                Assert.That(ws.VariantSubtag.Code, Is.EqualTo(variantCode));
            }

            // Now check that we can get the same tags by parsing the ID.

            LanguageSubtag languageSubtag;
            ScriptSubtag   scriptSubtag;
            RegionSubtag   regionSubtag;
            VariantSubtag  variantSubtag;

            LangTagUtils.GetSubtags(id, out languageSubtag, out scriptSubtag, out regionSubtag, out variantSubtag);
            Assert.That(languageSubtag.Code, Is.EqualTo(langCode));
            if (scriptCode == null)
            {
                Assert.That(scriptSubtag, Is.Null);
            }
            else
            {
                Assert.That(scriptSubtag.Code, Is.EqualTo(scriptCode));
            }
            if (regionCode == null)
            {
                Assert.That(regionSubtag, Is.Null);
            }
            else
            {
                Assert.That(regionSubtag.Code, Is.EqualTo(regionCode));
            }
            if (variantCode == null)
            {
                Assert.That(variantSubtag, Is.Null);
            }
            else
            {
                Assert.That(variantSubtag.Code, Is.EqualTo(variantCode));
            }
        }
Beispiel #10
0
        public void LanguageAndVariantTags()
        {
            // A new writing system has a Language tag of qaa. This is also its language tag. The others are null.
            var ws = new PalasoWritingSystem();

            VerifySubtagCodes(ws, "qaa", null, null, null, "qaa");
            VerifyComponents(ws, "qaa", "", "", "", "qaa");

            ws.LanguageSubtag = LangTagUtils.GetLanguageSubtag("en");
            VerifySubtagCodes(ws, "en", null, null, null, "en");
            VerifyComponents(ws, "en", "", "", "", "en");
            Assert.That(ws.LanguageName, Is.EqualTo("English"));

            ws.LanguageSubtag = new LanguageSubtag("kal", "Kalaba", true, "");
            Assert.That(ws.LanguageName, Is.EqualTo("Kalaba"));
            VerifySubtagCodes(ws, "kal", null, null, null, "qaa-x-kal");
            VerifyComponents(ws, "qaa", "", "", "x-kal", "qaa-x-kal");
            Assert.That(ws.LanguageSubtag.Name, Is.EqualTo("Kalaba"));

            // This is a region code that is valid, so we don't store it in the private-use area of our code.
            ws.RegionSubtag = LangTagUtils.GetRegionSubtag("QN");
            VerifySubtagCodes(ws, "kal", null, "QN", null, "qaa-QN-x-kal");
            VerifyComponents(ws, "qaa", "", "QN", "x-kal", "qaa-QN-x-kal");

            // This is a standard region (Norway).
            ws.RegionSubtag = LangTagUtils.GetRegionSubtag("NO");
            VerifySubtagCodes(ws, "kal", null, "NO", null, "qaa-NO-x-kal");
            VerifyComponents(ws, "qaa", "", "NO", "x-kal", "qaa-NO-x-kal");

            // A private region
            ws.RegionSubtag = LangTagUtils.GetRegionSubtag("ZD");
            VerifySubtagCodes(ws, "kal", null, "ZD", null, "qaa-QM-x-kal-ZD");
            VerifyComponents(ws, "qaa", "", "QM", "x-kal-ZD", "qaa-QM-x-kal-ZD");

            // Add a private script
            ws.ScriptSubtag = LangTagUtils.GetScriptSubtag("Zfdr");
            VerifySubtagCodes(ws, "kal", "Zfdr", "ZD", null, "qaa-Qaaa-QM-x-kal-Zfdr-ZD");
            VerifyComponents(ws, "qaa", "Qaaa", "QM", "x-kal-Zfdr-ZD", "qaa-Qaaa-QM-x-kal-Zfdr-ZD");

            // Change it to a standard one
            ws.ScriptSubtag = LangTagUtils.GetScriptSubtag("Phnx");
            VerifySubtagCodes(ws, "kal", "Phnx", "ZD", null, "qaa-Phnx-QM-x-kal-ZD");
            VerifyComponents(ws, "qaa", "Phnx", "QM", "x-kal-ZD", "qaa-Phnx-QM-x-kal-ZD");

            // To the standard private-use marker
            ws.ScriptSubtag = LangTagUtils.GetScriptSubtag("Qaaa");
            VerifySubtagCodes(ws, "kal", "Qaaa", "ZD", null, "qaa-Qaaa-QM-x-kal-Qaaa-ZD");
            VerifyComponents(ws, "qaa", "Qaaa", "QM", "x-kal-Qaaa-ZD", "qaa-Qaaa-QM-x-kal-Qaaa-ZD");


            // Back to the special one
            ws.ScriptSubtag = LangTagUtils.GetScriptSubtag("Zfdr");
            VerifySubtagCodes(ws, "kal", "Zfdr", "ZD", null, "qaa-Qaaa-QM-x-kal-Zfdr-ZD");
            VerifyComponents(ws, "qaa", "Qaaa", "QM", "x-kal-Zfdr-ZD", "qaa-Qaaa-QM-x-kal-Zfdr-ZD");

            // Add a standard variant
            ws.VariantSubtag = LangTagUtils.GetVariantSubtag("fonipa");
            VerifySubtagCodes(ws, "kal", "Zfdr", "ZD", "fonipa", "qaa-Qaaa-QM-fonipa-x-kal-Zfdr-ZD");
            VerifyComponents(ws, "qaa", "Qaaa", "QM", "fonipa-x-kal-Zfdr-ZD", "qaa-Qaaa-QM-fonipa-x-kal-Zfdr-ZD");

            // Change it to a combination one
            ws.VariantSubtag = LangTagUtils.GetVariantSubtag("fonipa-x-etic");
            VerifySubtagCodes(ws, "kal", "Zfdr", "ZD", "fonipa-x-etic", "qaa-Qaaa-QM-fonipa-x-kal-Zfdr-ZD-etic");
            VerifyComponents(ws, "qaa", "Qaaa", "QM", "fonipa-x-kal-Zfdr-ZD-etic", "qaa-Qaaa-QM-fonipa-x-kal-Zfdr-ZD-etic");

            // Back to no variant.
            ws.VariantSubtag = null;
            VerifySubtagCodes(ws, "kal", "Zfdr", "ZD", null, "qaa-Qaaa-QM-x-kal-Zfdr-ZD");
            VerifyComponents(ws, "qaa", "Qaaa", "QM", "x-kal-Zfdr-ZD", "qaa-Qaaa-QM-x-kal-Zfdr-ZD");

            // Try a double combination
            ws.VariantSubtag = LangTagUtils.GetVariantSubtag("fonipa-1996-x-etic-emic");
            VerifySubtagCodes(ws, "kal", "Zfdr", "ZD", "fonipa-1996-x-etic-emic", "qaa-Qaaa-QM-fonipa-1996-x-kal-Zfdr-ZD-etic-emic");
            VerifyComponents(ws, "qaa", "Qaaa", "QM", "fonipa-1996-x-kal-Zfdr-ZD-etic-emic", "qaa-Qaaa-QM-fonipa-1996-x-kal-Zfdr-ZD-etic-emic");

            // Drop a piece out of each
            ws.VariantSubtag = LangTagUtils.GetVariantSubtag("fonipa-x-etic");
            VerifySubtagCodes(ws, "kal", "Zfdr", "ZD", "fonipa-x-etic", "qaa-Qaaa-QM-fonipa-x-kal-Zfdr-ZD-etic");
            VerifyComponents(ws, "qaa", "Qaaa", "QM", "fonipa-x-kal-Zfdr-ZD-etic", "qaa-Qaaa-QM-fonipa-x-kal-Zfdr-ZD-etic");

            // Soemthing totally unknown
            ws.VariantSubtag = LangTagUtils.GetVariantSubtag("fonipa-x-blah");
            VerifySubtagCodes(ws, "kal", "Zfdr", "ZD", "fonipa-x-blah", "qaa-Qaaa-QM-fonipa-x-kal-Zfdr-ZD-blah");
            VerifyComponents(ws, "qaa", "Qaaa", "QM", "fonipa-x-kal-Zfdr-ZD-blah", "qaa-Qaaa-QM-fonipa-x-kal-Zfdr-ZD-blah");

            // Drop just the standard part
            ws.VariantSubtag = LangTagUtils.GetVariantSubtag("x-blah");
            VerifySubtagCodes(ws, "kal", "Zfdr", "ZD", "x-blah", "qaa-Qaaa-QM-x-kal-Zfdr-ZD-blah");
            VerifyComponents(ws, "qaa", "Qaaa", "QM", "x-kal-Zfdr-ZD-blah", "qaa-Qaaa-QM-x-kal-Zfdr-ZD-blah");

            // No longer a custom language
            ws.LanguageSubtag = LangTagUtils.GetLanguageSubtag("en");
            VerifySubtagCodes(ws, "en", "Zfdr", "ZD", "x-blah", "en-Qaaa-QM-x-Zfdr-ZD-blah");
            VerifyComponents(ws, "en", "Qaaa", "QM", "x-Zfdr-ZD-blah", "en-Qaaa-QM-x-Zfdr-ZD-blah");

            // No longer a custom script
            ws.ScriptSubtag = null;
            VerifySubtagCodes(ws, "en", null, "ZD", "x-blah", "en-QM-x-ZD-blah");
            VerifyComponents(ws, "en", "", "QM", "x-ZD-blah", "en-QM-x-ZD-blah");

            // No longer a custom region
            ws.RegionSubtag = null;
            VerifySubtagCodes(ws, "en", null, null, "x-blah", "en-x-blah");
            VerifyComponents(ws, "en", "", "", "x-blah", "en-x-blah");

            // No more variant
            ws.VariantSubtag = null;
            VerifySubtagCodes(ws, "en", null, null, null, "en");
            VerifyComponents(ws, "en", "", "", "", "en");
        }
		/// <summary>
		/// Persists all modified writing systems.
		/// </summary>
		public void Save()
		{
			lock (m_syncRoot)
			{
				DateTime now = DateTime.UtcNow;
				foreach (PalasoWritingSystem ws in m_localStore.AllWritingSystems)
				{
					if (ws.Modified || ws.DateModified.Ticks == 0)
						ws.DateModified = now;

					if (ws.MarkedForDeletion)
					{
						m_handleWss.Remove(ws.Handle);
						if (m_userWritingSystem == ws)
							m_userWritingSystem = null;
					}
				}
				m_localStore.Save();
				Settings.Default.LocalKeyboards = UnionSettingsKeyboardsWithLocalStore();
				Settings.Default.Save();
			}
		}
		public void LocalKeyboardsUnionLocalStore()
		{
			// Populate Settings.Default.LocalKeyboards
			Settings.Default.LocalKeyboards = "<keyboards>"
											+ "<keyboard ws=\"en\" layout=\"US\" locale=\"en-US\" />"
											+ "<keyboard ws=\"zh-CN-pinyin\" layout=\"US\" locale=\"en-US\" />"
											+ "<keyboard ws=\"zh-CN\" layout=\"Chinese (Simplified) - US Keyboard\" locale=\"zh-CN\" />"
											+ "</keyboards>";

			// Set up a local store with one conflicting and one additional keyboard
			var localStore = new LocalFileWritingSystemStore(PrepareTempStore("Store"));
			var ws = new PalasoWritingSystem
			{
				LanguageSubtag = new LanguageSubtag("en", "en", false, null),
				LocalKeyboard = Keyboard.Controller.CreateKeyboardDefinition("United States-Dvorak", "en-UK")
			};
			localStore.Set(ws);
			ws = new PalasoWritingSystem
			{
				LanguageSubtag = new LanguageSubtag("ko", "ko", false, null),
				LocalKeyboard = Keyboard.Controller.CreateKeyboardDefinition("US", "ta-IN")
			};
			localStore.Set(ws);
			var wsm = new TestPalasoWritingSystemManager(localStore);

			// SUT
			var resultXml = wsm.TestUnionSettingsKeyboardsWithLocalStore();

			// Parse resulting string into XElements
			var root = XElement.Parse(resultXml);
			var keyboardSettings = new Dictionary<string, XElement>();
			foreach (var kbd in root.Elements("keyboard"))
			{
				keyboardSettings[kbd.Attribute("ws").Value] = kbd;
			}

			Assert.AreEqual(4, keyboardSettings.Count, "Incorrect number of keyboards in Union");
			// the same
			Assert.AreEqual("US", keyboardSettings["zh-CN-pinyin"].Attribute("layout").Value, "Pinyin keyboard layout should not have changed");
			Assert.AreEqual("en-US", keyboardSettings["zh-CN-pinyin"].Attribute("locale").Value, "Pinyin keyboard locale should not have changed");
			Assert.AreEqual("Chinese (Simplified) - US Keyboard", keyboardSettings["zh-CN"].Attribute("layout").Value, "Chinese keyboard layout should not have changed");
			Assert.AreEqual("zh-CN", keyboardSettings["zh-CN"].Attribute("locale").Value, "Chinese keyboard locale should not have changed");
			// new or changed
			Assert.AreEqual("United States-Dvorak", keyboardSettings["en"].Attribute("layout").Value, "English keyboard layout should have changed");
			Assert.AreEqual("en-UK", keyboardSettings["en"].Attribute("locale").Value, "English keyboard locale should have changed");
			Assert.AreEqual("US", keyboardSettings["ko"].Attribute("layout").Value, "Korean keyboard layout should have been created");
			Assert.AreEqual("ta-IN", keyboardSettings["ko"].Attribute("locale").Value, "Korean keyboard locale should have been created");
		}