public void Write_ValidXml_XmlUpdated() { const string projectSettingsXml = @"<ProjectLexiconSettings> <WritingSystems> <WritingSystem id=""qaa-Qaaa-QM-x-kal-Fake-ZG-var1-var2-var3""> <Abbreviation>kal</Abbreviation> <LanguageName>Kalaba</LanguageName> <ScriptName>Fake</ScriptName> <RegionName>Zolrog</RegionName> </WritingSystem> </WritingSystems> </ProjectLexiconSettings>"; var settingsStore = new MemorySettingsStore { SettingsElement = XElement.Parse(projectSettingsXml) }; var projectSettingsDataMapper = new ProjectLexiconSettingsWritingSystemDataMapper(settingsStore); var ws1 = new WritingSystemDefinition("qaa-Qaaa-QM-x-kal-Fake-ZG-var1-var2-var3"); ws1.Abbreviation = "ka"; ws1.SpellCheckingId = "en_US"; ws1.LegacyMapping = "converter"; ws1.Keyboard = "Old Keyboard"; var scd = new SystemCollationDefinition { LanguageTag = "snarf" }; ws1.DefaultCollation = scd; projectSettingsDataMapper.Write(ws1); Assert.That(settingsStore.SettingsElement, Is.XmlEqualTo( @"<ProjectLexiconSettings> <WritingSystems> <WritingSystem id=""qaa-Qaaa-QM-x-kal-Fake-ZG-var1-var2-var3""> <Abbreviation>ka</Abbreviation> <SpellCheckingId>en_US</SpellCheckingId> <LegacyMapping>converter</LegacyMapping> <Keyboard>Old Keyboard</Keyboard> <SystemCollation>snarf</SystemCollation> </WritingSystem> </WritingSystems> </ProjectLexiconSettings>")); }
public void Migrate_OriginalFileContainsSystemCollationInfo_CollationInfoIsMigrated() { using (var environment = new TestEnvironment()) { environment.WriteLdmlFile( "test.ldml", LdmlContentForTests.Version0WithSystemCollationInfo()); var wsV0 = new WritingSystemDefinitionV0(); new LdmlAdaptorV0().Read(environment.FilePath("test.ldml"), wsV0); var migrator = new LdmlInFolderWritingSystemRepositoryMigrator(environment.LdmlPath, environment.OnMigrateCallback); migrator.Migrate(); var repo = new TestLdmlInFolderWritingSystemRepository(environment.LdmlPath); migrator.ResetRemovedProperties(repo); WritingSystemDefinition ws = repo.Get("de"); var scd = new SystemCollationDefinition {LanguageTag = "de"}; Assert.That(ws.DefaultCollation.ValueEquals(scd), Is.True); } }
public override void Migrate(string sourceFilePath, string destinationFilePath) { string sourceFileName = Path.GetFileName(sourceFilePath); var writingSystemDefinitionV1 = new WritingSystemDefinitionV1(); new LdmlAdaptorV1().Read(sourceFilePath, writingSystemDefinitionV1); string abbreviation = writingSystemDefinitionV1.Abbreviation; float defaultFontSize = writingSystemDefinitionV1.DefaultFontSize; string keyboard = writingSystemDefinitionV1.Keyboard; string spellCheckingId = writingSystemDefinitionV1.SpellCheckingId; string defaultFontName = writingSystemDefinitionV1.DefaultFontName; string languageName = writingSystemDefinitionV1.LanguageName.IsOneOf("Unknown Language", "Language Not Listed") ? string.Empty : writingSystemDefinitionV1.LanguageName; string variant, privateUse; IetfLanguageTag.SplitVariantAndPrivateUse(writingSystemDefinitionV1.Variant, out variant, out privateUse); var langTagCleaner = new IetfLanguageTagCleaner(writingSystemDefinitionV1.Language, writingSystemDefinitionV1.Script, writingSystemDefinitionV1.Region, variant, privateUse); langTagCleaner.Clean(); string langTag = IetfLanguageTag.Canonicalize(langTagCleaner.GetCompleteTag()); List <string> knownKeyboards = writingSystemDefinitionV1.KnownKeyboards.Select(k => string.IsNullOrEmpty(k.Locale) ? k.Layout : string.Format("{0}_{1}", k.Locale, k.Layout)).ToList(); bool isGraphiteEnabled = false; string legacyMapping = string.Empty; string scriptName = string.Empty; string regionName = string.Empty; string variantName = string.Empty; SystemCollationDefinition scd = null; // Create system collation definition if applicable if ((writingSystemDefinitionV1.SortUsing == WritingSystemDefinitionV1.SortRulesType.OtherLanguage) && (!string.IsNullOrEmpty(writingSystemDefinitionV1.SortRules))) { scd = new SystemCollationDefinition { LanguageTag = writingSystemDefinitionV1.SortRules } } ; // Migrate fields from legacy fw namespace, and then remove fw namespace XElement ldmlElem = XElement.Load(sourceFilePath); XElement fwElem = ldmlElem.Elements("special").FirstOrDefault(e => !string.IsNullOrEmpty((string)e.Attribute(XNamespace.Xmlns + "fw"))); if (fwElem != null) { XElement graphiteEnabledElem = fwElem.Element(FW + "graphiteEnabled"); if (graphiteEnabledElem != null) { if (!bool.TryParse((string)graphiteEnabledElem.Attribute("value"), out isGraphiteEnabled)) { isGraphiteEnabled = false; } } // LegacyMapping XElement legacyMappingElem = fwElem.Element(FW + "legacyMapping"); if (legacyMappingElem != null) { legacyMapping = (string)legacyMappingElem.Attribute("value"); } // ScriptName XElement scriptNameElem = fwElem.Element(FW + "scriptName"); if (scriptNameElem != null) { scriptName = (string)scriptNameElem.Attribute("value"); } // RegionName XElement regionNameElem = fwElem.Element(FW + "regionName"); if (regionNameElem != null) { regionName = (string)regionNameElem.Attribute("value"); } // VariantName XElement variantNameElem = fwElem.Element(FW + "variantName"); if (variantNameElem != null) { variantName = (string)variantNameElem.Attribute("value"); } } // Record the details for use in PostMigrate where we change the file name to match the ieft language tag where we can. var migrationInfo = new LdmlMigrationInfo(sourceFileName) { LanguageTagBeforeMigration = writingSystemDefinitionV1.Bcp47Tag, LanguageTagAfterMigration = langTag, RemovedPropertiesSetter = ws => { if (!string.IsNullOrEmpty(abbreviation)) { ws.Abbreviation = abbreviation; } if (defaultFontSize != 0) { ws.DefaultFontSize = defaultFontSize; } if (!string.IsNullOrEmpty(keyboard)) { ws.Keyboard = keyboard; } if (!string.IsNullOrEmpty(spellCheckingId)) { ws.SpellCheckingId = spellCheckingId; } if (!string.IsNullOrEmpty(defaultFontName)) { ws.DefaultFont = ws.Fonts[defaultFontName]; } if (!string.IsNullOrEmpty(languageName)) { ws.Language = new LanguageSubtag(ws.Language, languageName); } ws.IsGraphiteEnabled = isGraphiteEnabled; if (!string.IsNullOrEmpty(legacyMapping)) { ws.LegacyMapping = legacyMapping; } if (!string.IsNullOrEmpty(scriptName) && ws.Script != null && ws.Script.IsPrivateUse) { ws.Script = new ScriptSubtag(ws.Script, scriptName); } if (!string.IsNullOrEmpty(regionName) && ws.Region != null && ws.Region.IsPrivateUse) { ws.Region = new RegionSubtag(ws.Region, regionName); } if (scd != null) { ws.DefaultCollation = scd; } foreach (string keyboardId in knownKeyboards) { IKeyboardDefinition kd; if (!Keyboard.Controller.TryGetKeyboard(keyboardId, out kd)) { kd = Keyboard.Controller.CreateKeyboard(keyboardId, KeyboardFormat.Unknown, Enumerable.Empty <string>()); } ws.KnownKeyboards.Add(kd); } } }; _migrationInfo.Add(migrationInfo); // Store things that stay in ldml but are being moved: WindowsLcid, variantName, font, known keyboards, collations, font features, character sets // misc properties var staging = new Staging { WindowsLcid = writingSystemDefinitionV1.WindowsLcid, DefaultFontName = writingSystemDefinitionV1.DefaultFontName, SortUsing = writingSystemDefinitionV1.SortUsing, SortRules = writingSystemDefinitionV1.SortRules, }; // Determine if variantName is non-common private use before preserving it if (!string.IsNullOrEmpty(variantName)) { int index = IetfLanguageTag.GetIndexOfFirstNonCommonPrivateUseVariant(IetfLanguageTag.GetVariantSubtags(migrationInfo.LanguageTagAfterMigration)); if (index > -1) { staging.VariantName = variantName; } } if (fwElem != null) { // DefaultFontFeatures XElement fontFeatsElem = fwElem.Element(FW + "defaultFontFeatures"); if (fontFeatsElem != null && !string.IsNullOrEmpty(staging.DefaultFontName)) { staging.DefaultFontFeatures = (string)fontFeatsElem.Attribute("value"); } //MatchedPairs, PunctuationPatterns, QuotationMarks deprecated // Valid Chars XElement validCharsElem = fwElem.Element(FW + "validChars"); if (validCharsElem != null) { try { var fwValidCharsElem = XElement.Parse((string)validCharsElem.Attribute("value")); AddCharacterSet(fwValidCharsElem, staging, "WordForming", "main"); AddCharacterSet(fwValidCharsElem, staging, "Numeric", "numeric"); AddCharacterSet(fwValidCharsElem, staging, "Other", "punctuation"); } catch (XmlException) { ParseLegacyWordformingCharOverridesFile(staging); } } } _staging[sourceFileName] = staging; }
public void Read_ValidXml_SetsAllProperties() { const string projectSettingsXml = @"<ProjectLexiconSettings> <WritingSystems> <WritingSystem id=""qaa-Qaaa-QM-x-kal-Fake-ZG-var1-var2""> <Abbreviation>kal</Abbreviation> <LanguageName>Kalaba</LanguageName> <ScriptName>Fake</ScriptName> <RegionName>Zolrog</RegionName> <SystemCollation>snarf</SystemCollation> </WritingSystem> <WritingSystem id=""fr-FR""> <SpellCheckingId>fr_FR</SpellCheckingId> <LegacyMapping>converter</LegacyMapping> <Keyboard>Old Keyboard</Keyboard> </WritingSystem> </WritingSystems> </ProjectLexiconSettings>"; var projectSettingsDataMapper = new ProjectLexiconSettingsWritingSystemDataMapper(new MemorySettingsStore { SettingsElement = XElement.Parse(projectSettingsXml) }); var ws1 = new WritingSystemDefinition("qaa-Qaaa-QM-x-kal-Fake-ZG-var1-var2"); projectSettingsDataMapper.Read(ws1); Assert.That(ws1.Abbreviation, Is.EqualTo("kal")); Assert.That(ws1.Language.Name, Is.EqualTo("Kalaba")); Assert.That(ws1.Script.Name, Is.EqualTo("Fake")); Assert.That(ws1.Region.Name, Is.EqualTo("Zolrog")); Assert.That(ws1.SpellCheckingId, Is.EqualTo(string.Empty)); Assert.That(ws1.LegacyMapping, Is.EqualTo(string.Empty)); Assert.That(ws1.Keyboard, Is.EqualTo(string.Empty)); var scd = new SystemCollationDefinition { LanguageTag = "snarf" }; Assert.That(ws1.DefaultCollation, Is.ValueEqualTo(scd)); var ws2 = new WritingSystemDefinition("fr-FR"); projectSettingsDataMapper.Read(ws2); Assert.That(ws2.Abbreviation, Is.EqualTo("fr")); Assert.That(ws2.Language.Name, Is.EqualTo("French")); Assert.That(ws2.Script.Name, Is.EqualTo("Latin")); Assert.That(ws2.Region.Name, Is.EqualTo("France")); Assert.That(ws2.Variants, Is.Empty); Assert.That(ws2.SpellCheckingId, Is.EqualTo("fr_FR")); Assert.That(ws2.LegacyMapping, Is.EqualTo("converter")); Assert.That(ws2.Keyboard, Is.EqualTo("Old Keyboard")); var ws3 = new WritingSystemDefinition("es"); projectSettingsDataMapper.Read(ws3); Assert.That(ws3.Abbreviation, Is.EqualTo("es")); Assert.That(ws3.Language.Name, Is.EqualTo("Spanish")); Assert.That(ws3.Script.Name, Is.EqualTo("Latin")); Assert.That(ws3.Region, Is.Null); Assert.That(ws3.Variants, Is.Empty); Assert.That(ws3.SpellCheckingId, Is.EqualTo(string.Empty)); Assert.That(ws3.LegacyMapping, Is.EqualTo(string.Empty)); Assert.That(ws3.Keyboard, Is.EqualTo(string.Empty)); }
public SystemCollationDefinition(SystemCollationDefinition scd) : base(scd) { _languageTag = scd._languageTag; }
public override void Migrate(string sourceFilePath, string destinationFilePath) { string sourceFileName = Path.GetFileName(sourceFilePath); var writingSystemDefinitionV1 = new WritingSystemDefinitionV1(); new LdmlAdaptorV1().Read(sourceFilePath, writingSystemDefinitionV1); string abbreviation = writingSystemDefinitionV1.Abbreviation; float defaultFontSize = writingSystemDefinitionV1.DefaultFontSize; string keyboard = writingSystemDefinitionV1.Keyboard; string spellCheckingId = writingSystemDefinitionV1.SpellCheckingId; string defaultFontName = writingSystemDefinitionV1.DefaultFontName; string languageName = writingSystemDefinitionV1.LanguageName.IsOneOf("Unknown Language", "Language Not Listed") ? string.Empty : writingSystemDefinitionV1.LanguageName; string variant, privateUse; IetfLanguageTag.SplitVariantAndPrivateUse(writingSystemDefinitionV1.Variant, out variant, out privateUse); var langTagCleaner = new IetfLanguageTagCleaner(writingSystemDefinitionV1.Language, writingSystemDefinitionV1.Script, writingSystemDefinitionV1.Region, variant, privateUse); langTagCleaner.Clean(); string langTag = IetfLanguageTag.Canonicalize(langTagCleaner.GetCompleteTag()); List<string> knownKeyboards = writingSystemDefinitionV1.KnownKeyboards.Select(k => string.IsNullOrEmpty(k.Locale) ? k.Layout : string.Format("{0}_{1}", k.Locale, k.Layout)).ToList(); bool isGraphiteEnabled = false; string legacyMapping = string.Empty; string scriptName = string.Empty; string regionName = string.Empty; string variantName = string.Empty; SystemCollationDefinition scd = null; // Create system collation definition if applicable if ((writingSystemDefinitionV1.SortUsing == WritingSystemDefinitionV1.SortRulesType.OtherLanguage) && (!string.IsNullOrEmpty(writingSystemDefinitionV1.SortRules))) scd = new SystemCollationDefinition { LanguageTag = writingSystemDefinitionV1.SortRules }; // Migrate fields from legacy fw namespace, and then remove fw namespace XElement ldmlElem = XElement.Load(sourceFilePath); XElement fwElem = ldmlElem.Elements("special").FirstOrDefault(e => !string.IsNullOrEmpty((string) e.Attribute(XNamespace.Xmlns + "fw"))); if (fwElem != null) { XElement graphiteEnabledElem = fwElem.Element(FW + "graphiteEnabled"); if (graphiteEnabledElem != null) { if (!bool.TryParse((string) graphiteEnabledElem.Attribute("value"), out isGraphiteEnabled)) isGraphiteEnabled = false; } // LegacyMapping XElement legacyMappingElem = fwElem.Element(FW + "legacyMapping"); if (legacyMappingElem != null) legacyMapping = (string) legacyMappingElem.Attribute("value"); // ScriptName XElement scriptNameElem = fwElem.Element(FW + "scriptName"); if (scriptNameElem != null) scriptName = (string) scriptNameElem.Attribute("value"); // RegionName XElement regionNameElem = fwElem.Element(FW + "regionName"); if (regionNameElem != null) regionName = (string) regionNameElem.Attribute("value"); // VariantName XElement variantNameElem = fwElem.Element(FW + "variantName"); if (variantNameElem != null) variantName = (string) variantNameElem.Attribute("value"); } // Record the details for use in PostMigrate where we change the file name to match the ieft language tag where we can. var migrationInfo = new LdmlMigrationInfo(sourceFileName) { LanguageTagBeforeMigration = writingSystemDefinitionV1.Bcp47Tag, LanguageTagAfterMigration = langTag, RemovedPropertiesSetter = ws => { if (!string.IsNullOrEmpty(abbreviation)) ws.Abbreviation = abbreviation; if (defaultFontSize != 0) ws.DefaultFontSize = defaultFontSize; if (!string.IsNullOrEmpty(keyboard)) ws.Keyboard = keyboard; if (!string.IsNullOrEmpty(spellCheckingId)) ws.SpellCheckingId = spellCheckingId; if (!string.IsNullOrEmpty(defaultFontName)) ws.DefaultFont = ws.Fonts[defaultFontName]; if (!string.IsNullOrEmpty(languageName)) ws.Language = new LanguageSubtag(ws.Language, languageName); ws.IsGraphiteEnabled = isGraphiteEnabled; if (!string.IsNullOrEmpty(legacyMapping)) ws.LegacyMapping = legacyMapping; if (!string.IsNullOrEmpty(scriptName) && ws.Script != null && ws.Script.IsPrivateUse) ws.Script = new ScriptSubtag(ws.Script, scriptName); if (!string.IsNullOrEmpty(regionName) && ws.Region != null && ws.Region.IsPrivateUse) ws.Region = new RegionSubtag(ws.Region, regionName); if (scd != null) ws.DefaultCollation = scd; foreach (string keyboardId in knownKeyboards) { IKeyboardDefinition kd; if (!Keyboard.Controller.TryGetKeyboard(keyboardId, out kd)) kd = Keyboard.Controller.CreateKeyboard(keyboardId, KeyboardFormat.Unknown, Enumerable.Empty<string>()); ws.KnownKeyboards.Add(kd); } } }; _migrationInfo.Add(migrationInfo); // Store things that stay in ldml but are being moved: WindowsLcid, variantName, font, known keyboards, collations, font features, character sets // misc properties var staging = new Staging { WindowsLcid = writingSystemDefinitionV1.WindowsLcid, DefaultFontName = writingSystemDefinitionV1.DefaultFontName, SortUsing = writingSystemDefinitionV1.SortUsing, SortRules = writingSystemDefinitionV1.SortRules, }; // Determine if variantName is non-common private use before preserving it if (!string.IsNullOrEmpty(variantName)) { int index = IetfLanguageTag.GetIndexOfFirstNonCommonPrivateUseVariant(IetfLanguageTag.GetVariantSubtags(migrationInfo.LanguageTagAfterMigration)); if (index > -1) staging.VariantName = variantName; } if (fwElem != null) { // DefaultFontFeatures XElement fontFeatsElem = fwElem.Element(FW + "defaultFontFeatures"); if (fontFeatsElem != null && !string.IsNullOrEmpty(staging.DefaultFontName)) staging.DefaultFontFeatures = (string) fontFeatsElem.Attribute("value"); //MatchedPairs, PunctuationPatterns, QuotationMarks deprecated // Valid Chars XElement validCharsElem = fwElem.Element(FW + "validChars"); if (validCharsElem != null) { try { var fwValidCharsElem = XElement.Parse((string) validCharsElem.Attribute("value")); AddCharacterSet(fwValidCharsElem, staging, "WordForming", "main"); AddCharacterSet(fwValidCharsElem, staging, "Numeric", "numeric"); AddCharacterSet(fwValidCharsElem, staging, "Other", "punctuation"); } catch (XmlException) { ParseLegacyWordformingCharOverridesFile(staging); } } } _staging[sourceFileName] = staging; }
/// <summary> /// Creates a TreeNode tree along genres populated by the texts that claim them. /// The list of textsWithNoGenre is also populated. /// Recursively descend the genre tree and duplicate parts that have corresponding texts. /// </summary> /// <param name="parent">The parent to attach the genres to. If null, nothing is done.</param> /// <param name="genreList">The owning sequence of genres - its a tree.</param> /// <param name="allTexts">The flat list of all texts in the project.</param> private static void LoadTextsFromGenres(TreeNode parent, ILcmOwningSequence <ICmPossibility> genreList, IEnumerable <LCModel.IText> allTexts) { if (parent == null) { return; } var sortedGenreList = new List <ICmPossibility>(genreList); var sorter = new CmPossibilitySorter(); sortedGenreList.Sort(sorter); foreach (var gen in sortedGenreList) { // This tree node is added to genreTreeNodes if there are texts or children var genItem = new TreeNode(gen.ChooserNameTS.Text); // LT-12179: Create a List for collecting selected tree nodes which we will later sort // before actually adding them to the tree: var sortedNodes = new List <TreeNode>(); var foundFirstText = false; foreach (var tex in allTexts) { // This tex may not have a genre or it may claim to be in more than one if (!Enumerable.Contains(tex.GenresRC, gen)) { continue; } var texItem = new TreeNode(tex.ChooserNameTS.Text) { Tag = tex.ContentsOA, Name = "Text" }; // LT-12179: Add the new TreeNode to the (not-yet-)sorted list: sortedNodes.Add(texItem); // LT-12179: If this is the first tex we've added, establish the collator's details // according to the writing system at the start of the tex: if (foundFirstText) { continue; } foundFirstText = true; } // Always use the system collation definition. Texts have different writing systems anyhow. var wsCollator = new SystemCollationDefinition(); // LT-12179: if (foundFirstText) { // Order the TreeNodes alphabetically: sortedNodes.Sort((x, y) => wsCollator.Collator.Compare(x.Text, y.Text)); // Add the TreeNodes to the tree: genItem.Nodes.AddRange(sortedNodes.ToArray()); } if (gen.SubPossibilitiesOS.Count > 0) { // Descend to the child genres regardless if there were texts assigned to this genre LoadTextsFromGenres(genItem, gen.SubPossibilitiesOS, allTexts); } //Add the node even if there are no texts that point to this genre. genItem.Tag = gen; // ICmPossibility genItem.Name = "Genre"; parent.Nodes.Add(genItem); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Load texts by Genre into the texts tree view. /// </summary> /// <returns>A control tree of the Texts in the project</returns> /// ------------------------------------------------------------------------------------ private TreeNode LoadTextsByGenreAndWithoutGenre() { if (m_cache.LanguageProject.GenreListOA == null) { return(null); } var genreList = m_cache.LanguageProject.GenreListOA.PossibilitiesOS; Debug.Assert(genreList != null); var allTexts = m_cache.ServiceLocator.GetInstance <ITextRepository>().AllInstances(); if (allTexts == null) { return(null); } // Title node for all texts, Biblical and otherwise var textsNode = new TreeNode("All Texts in Genres and not in Genres") { Name = "Texts" }; // For each genre, find the texts that claim it LoadTextsFromGenres(textsNode, genreList, allTexts); var textsWithNoGenre = new List <TreeNode>(); // and get the ones with no genre // LT-12179: Create a List for collecting selected tree nodes which we will later sort // before actually adding them to the tree: var foundFirstText = false; foreach (var tex in allTexts) { if (tex.GenresRC.Any()) { continue; } var texItem = new TreeNode(tex.ChooserNameTS.Text) { Tag = tex.ContentsOA, Name = "Text" }; textsWithNoGenre.Add(texItem); // LT-12179: If this is the first tex we've added, establish the collator's details // according to the writing system at the start of the tex: if (foundFirstText) { continue; } foundFirstText = true; } if (!textsWithNoGenre.Any()) { return(textsNode); } // Just grab a system collator since text titles can be in various languages. Sorting by any one ws is going to // do something wrong part of the time anyhow. var wsCollator = new SystemCollationDefinition(); // LT-12179: Order the TreeNodes alphabetically: try { textsWithNoGenre.Sort((x, y) => wsCollator.Collator.Compare(x.Text, y.Text)); } catch (AccessViolationException) { // sort out sorting troubles later. // icu.net 2.5.4+Branch.master.Sha.aa2e04611b4... can throw an AccessViolationException in // RuleBasedCollator.Compare for yet-unknown reasons. See // https://github.com/sillsdev/icu-dotnet/issues/130 and LT-20194. // This may be resolved in the current version of ICU. } // Make a TreeNode for the texts with no known genre var woGenreTreeNode = new TreeNode("No Genre", textsWithNoGenre.ToArray()) { Name = "TextsWoGenre" }; textsNode.Nodes.Add(woGenreTreeNode); return(textsNode); }