Skip to content

Commit

Permalink
SF-2908 Fix crash when syncing specific Paratext Resources (#2669)
Browse files Browse the repository at this point in the history
  • Loading branch information
pmachapman authored Aug 22, 2024
1 parent 39b110f commit 7e91fbc
Showing 1 changed file with 70 additions and 2 deletions.
72 changes: 70 additions & 2 deletions src/SIL.XForge.Scripture/Services/ParatextService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
using Paratext.Data;
using Paratext.Data.Languages;
using Paratext.Data.ProjectComments;
using Paratext.Data.ProjectFileAccess;
using Paratext.Data.ProjectSettingsAccess;
using Paratext.Data.RegistryServerAccess;
using Paratext.Data.Repository;
Expand Down Expand Up @@ -2355,6 +2356,13 @@ bool needsToBeCloned
{
if (resource.InstallableResource != null)
{
// Correct the language code for old resources
LanguageId? overrideLanguageId = null;
if (DetermineBestLanguageForResource(resource.InstallableResource.ExistingScrText))
{
overrideLanguageId = resource.InstallableResource.ExistingScrText?.Settings.LanguageID;
}

// Install the resource if it is missing or out of date
if (
!resource.IsInstalled
Expand All @@ -2364,6 +2372,12 @@ bool needsToBeCloned
{
resource.InstallableResource.Install();
needsToBeCloned = true;

// On first install, we will now have an existing ScrText, so check the language is OK
if (DetermineBestLanguageForResource(resource.InstallableResource.ExistingScrText))
{
overrideLanguageId = resource.InstallableResource.ExistingScrText?.Settings.LanguageID;
}
}

// Extract the resource to the source directory
Expand All @@ -2372,7 +2386,7 @@ bool needsToBeCloned
string path = LocalProjectDir(targetParatextId);
_fileSystemService.CreateDirectory(path);
resource.InstallableResource.ExtractToDirectory(path);
MigrateResourceIfRequired(username, targetParatextId);
MigrateResourceIfRequired(username, targetParatextId, overrideLanguageId);
}
}
else
Expand All @@ -2381,13 +2395,58 @@ bool needsToBeCloned
}
}

/// <summary>
/// Determines the best language for a resource project
/// </summary>
/// <param name="scrText">The scripture text for the resource.</param>
/// <returns><c>true</c> if the project language was overridden by the DBL; otherwise, <c>false</c>.</returns>
/// <remarks>
/// <para>
/// This is reimplemented from <c>Paratext.Migration.MigrateLanguage.DetermineBestLangIdToUseForResource()</c>.
/// </para>
/// <para>
/// Because resources are not written to (as they are readonly), this should be run before using the LanguageID.
/// </para>
/// </remarks>
private static bool DetermineBestLanguageForResource(ScrText? scrText)
{
// If we do not have a ScrText, or this is not a resource, do not determine the language
if (scrText is null || !scrText.IsResourceProject)
{
return false;
}

// Get the language identifier from the .SSF file
string? languageIdLDML = scrText.Settings.LanguageID?.Id;

// Get the language identifier embedded in the .P8Z folder structure: .dbl\language\iso
string languageIdDBL = ((ZippedProjectFileManagerBase)scrText.FileManager).DBLResourceSettings.LanguageIso639_3;
LanguageId langIdDBL = LanguageId.FromEthnologueCode(languageIdDBL);
if (string.IsNullOrEmpty(languageIdLDML))
{
scrText.Settings.LanguageID = langIdDBL;
return true;
}

LanguageId langIdLDML = LanguageId.FromEthnologueCode(languageIdLDML);
if (langIdLDML.Code == langIdDBL.Code)
{
scrText.Settings.LanguageID = langIdLDML;
return false;
}

scrText.Settings.LanguageID = langIdDBL;
return true;
}

/// <summary>
/// Migrates a Paratext Resource, if required.
/// </summary>
/// <param name="username">The username.</param>
/// <param name="paratextId">The paratext project identifier.</param>
/// <param name="overrideLanguage">The language to override, if the project's language is incorrect.</param>
/// <remarks>This only performs one basic migration. Full migration can only be performed by Paratext.</remarks>
private void MigrateResourceIfRequired(string username, string paratextId)
private void MigrateResourceIfRequired(string username, string paratextId, LanguageId? overrideLanguage)
{
// Ensure that we have the ScrText to migrate
using ScrText scrText = ScrTextCollection.FindById(username, paratextId);
Expand All @@ -2396,6 +2455,15 @@ private void MigrateResourceIfRequired(string username, string paratextId)
return;
}

// Migrate the language id if it is missing. It will be missing as the project has changed from a resource (p8z)
// to a project (directory based), and we did not write to the p8z file as Paratext does in its migrators.
// The ScrText created above will not have the values defined in DetermineBestLanguageForResource() above, so
// we will need to override them again before migrating the LDML (an action which requires the LanguageID).
if (overrideLanguage is not null)
{
scrText.Settings.LanguageID = overrideLanguage;
}

// Perform a simple migration of the Paratext 7 LDML file to the new Paratext 8+ location.
// Paratext performs a much more complex migration, but we do not need that level of detail.
// If the publisher updates this resource, this file will be overwritten with the fully migrated language file,
Expand Down

0 comments on commit 7e91fbc

Please sign in to comment.