2019-12-26 23:01:54 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2016-01-14 08:11:47 -05:00
using System ;
using System.Collections.Generic ;
using System.IO ;
using AutomationTool ;
using UnrealBuildTool ;
2020-12-21 23:07:37 -04:00
using EpicGames.Core ;
2021-07-21 14:15:40 -04:00
using System.Threading.Tasks ;
2021-08-30 10:42:00 -04:00
using System.Reflection ;
2023-03-09 14:51:40 -05:00
using Microsoft.Extensions.Logging ;
using static AutomationTool . CommandUtils ;
2016-01-14 08:11:47 -05:00
namespace EpicGames.Localization
{
2019-01-21 12:57:05 -05:00
public class ProjectImportExportInfo
2019-01-21 11:07:47 -05:00
{
2019-01-21 12:57:05 -05:00
public ProjectImportExportInfo ( string InDestinationPath , string InManifestName , string InArchiveName , string InPortableObjectName , string InNativeCulture , IReadOnlyList < string > InCulturesToGenerate , bool InUseCultureDirectory )
2019-01-21 11:07:47 -05:00
{
2019-01-21 12:57:05 -05:00
DestinationPath = InDestinationPath ;
ManifestName = InManifestName ;
ArchiveName = InArchiveName ;
PortableObjectName = InPortableObjectName ;
NativeCulture = InNativeCulture ;
CulturesToGenerate = InCulturesToGenerate ;
bUseCultureDirectory = InUseCultureDirectory ;
}
/** The destination path for the files containing the gathered data for this project (extracted from its config file - relative to the root working directory for the commandlet) */
public string DestinationPath { get ; private set ; }
/** The name to use for this projects manifest file (extracted from its config file) */
public string ManifestName { get ; private set ; }
/** The name to use for this projects archive file (extracted from its config file) */
public string ArchiveName { get ; private set ; }
/** The name to use for this projects portable object file (extracted from its config file) */
public string PortableObjectName { get ; private set ; }
/** The native culture for this project (extracted from its config file) */
public string NativeCulture { get ; private set ; }
/** The cultures to generate for this project (extracted from its config file) */
public IReadOnlyList < string > CulturesToGenerate { get ; private set ; }
/** True if we should use a per-culture directly when importing/exporting */
public bool bUseCultureDirectory { get ; private set ; }
/** The platform names that we have split into sub-folders */
public IReadOnlyList < string > SplitPlatformNames { get ; private set ; }
/** The platforms sub-folder */
public const string PlatformLocalizationFolderName = "Platforms" ;
public void CalculateSplitPlatformNames ( string RootWorkingDirectory )
{
// Is this isn't a single culture import/export, then also check for split platform sub-folders
var NewSplitPlatformNames = new List < string > ( ) ;
if ( bUseCultureDirectory )
2019-01-21 11:07:47 -05:00
{
2019-01-21 12:57:05 -05:00
var PlatformSourceDirectory = new DirectoryReference ( CommandUtils . CombinePaths ( RootWorkingDirectory , DestinationPath , PlatformLocalizationFolderName ) ) ;
if ( DirectoryReference . Exists ( PlatformSourceDirectory ) )
2019-01-21 11:07:47 -05:00
{
2019-01-21 12:57:05 -05:00
foreach ( DirectoryReference FoundDirectory in DirectoryReference . EnumerateDirectories ( PlatformSourceDirectory , "*" , SearchOption . TopDirectoryOnly ) )
{
string SplitPlatformName = CommandUtils . GetLastDirectoryName ( FoundDirectory . FullName ) ;
NewSplitPlatformNames . Add ( SplitPlatformName ) ;
}
2019-01-21 11:07:47 -05:00
}
}
2019-01-21 12:57:05 -05:00
SplitPlatformNames = NewSplitPlatformNames ;
2019-01-21 11:07:47 -05:00
}
2016-01-14 08:11:47 -05:00
} ;
2019-01-21 12:57:05 -05:00
public class ProjectStepInfo
2016-01-14 08:11:47 -05:00
{
2019-01-21 12:57:05 -05:00
public ProjectStepInfo ( string InName , string InLocalizationConfigFile )
2017-05-10 11:49:32 -04:00
{
2019-01-21 12:57:05 -05:00
Name = InName ;
LocalizationConfigFile = InLocalizationConfigFile ;
2017-05-10 11:49:32 -04:00
}
2019-01-21 12:57:05 -05:00
/** The name of this localization step */
public string Name { get ; private set ; }
/** Absolute path to this steps localization config file */
public string LocalizationConfigFile { get ; private set ; }
} ;
public class ProjectInfo
{
public ProjectInfo ( string InProjectName , IReadOnlyList < ProjectStepInfo > InLocalizationSteps , ProjectImportExportInfo InImportInfo , ProjectImportExportInfo InExportInfo )
2016-01-14 08:11:47 -05:00
{
2019-01-21 12:57:05 -05:00
ProjectName = InProjectName ;
LocalizationSteps = InLocalizationSteps ;
ImportInfo = InImportInfo ;
ExportInfo = InExportInfo ;
}
2024-01-18 19:28:00 -05:00
public List < string > GetConfigFilesToRun ( List < string > RequestedLocalizationStepNames )
{
List < string > ConfigFiles = new ( ) ;
foreach ( var LocalizationStep in LocalizationSteps )
{
if ( RequestedLocalizationStepNames . Contains ( LocalizationStep . Name ) )
{
ConfigFiles . Add ( LocalizationStep . LocalizationConfigFile ) ;
}
}
return ConfigFiles ;
}
2019-01-21 12:57:05 -05:00
/** The name of this project */
public string ProjectName { get ; private set ; }
/** Path to this projects localization step data - ordered so that iterating them runs in the correct order */
public IReadOnlyList < ProjectStepInfo > LocalizationSteps { get ; private set ; }
/** Config data used by the PO file import process */
public ProjectImportExportInfo ImportInfo { get ; private set ; }
/** Config data used by the PO file export process */
public ProjectImportExportInfo ExportInfo { get ; private set ; }
} ;
public abstract class LocalizationProvider
{
public struct LocalizationProviderArgs
{
public string RootWorkingDirectory ;
public string RootLocalizationTargetDirectory ;
public string RemoteFilenamePrefix ;
public BuildCommand Command ;
public int PendingChangeList ;
} ;
public LocalizationProvider ( LocalizationProviderArgs InArgs )
{
RootWorkingDirectory = InArgs . RootWorkingDirectory ;
RemoteFilenamePrefix = InArgs . RemoteFilenamePrefix ;
Command = InArgs . Command ;
PendingChangeList = InArgs . PendingChangeList ;
LocalizationBranchName = Command . ParseParamValue ( "LocalizationBranch" ) ;
bUploadAllCultures = Command . ParseParam ( "UploadAllCultures" ) ;
}
public virtual string GetLocalizationProviderId ( )
{
throw new AutomationException ( "Unimplemented GetLocalizationProviderId." ) ;
}
2021-07-21 14:15:40 -04:00
public async virtual Task InitializeProjectWithLocalizationProvider ( string ProjectName , ProjectImportExportInfo ProjectImportInfo )
2019-01-21 12:57:05 -05:00
{
2021-07-21 14:15:40 -04:00
await Task . CompletedTask ;
2019-01-21 12:57:05 -05:00
}
2021-07-21 14:15:40 -04:00
public async virtual Task DownloadProjectFromLocalizationProvider ( string ProjectName , ProjectImportExportInfo ProjectImportInfo )
2019-01-21 12:57:05 -05:00
{
2021-07-21 14:15:40 -04:00
await Task . FromException ( new NotImplementedException ( ) ) ;
}
public async virtual Task UploadProjectToLocalizationProvider ( string ProjectName , ProjectImportExportInfo ProjectExportInfo )
{
await Task . FromException ( new NotImplementedException ( ) ) ;
2019-01-21 12:57:05 -05:00
}
public static LocalizationProvider GetLocalizationProvider ( string InLocalizationProviderId , LocalizationProvider . LocalizationProviderArgs InLocalizationProviderArgs )
{
if ( String . IsNullOrEmpty ( InLocalizationProviderId ) )
2016-01-14 08:11:47 -05:00
{
2019-01-21 12:57:05 -05:00
return null ;
}
if ( CachedLocalizationProviderTypes = = null )
{
// Find all types that derive from LocalizationProvider in any of our DLLs
CachedLocalizationProviderTypes = new Dictionary < string , Type > ( ) ;
2021-08-30 10:42:00 -04:00
foreach ( Assembly Dll in ScriptManager . AllScriptAssemblies )
2016-01-14 08:11:47 -05:00
{
2019-01-21 12:57:05 -05:00
var AllTypes = Dll . GetTypes ( ) ;
foreach ( var PotentialLocalizationNodeType in AllTypes )
2016-01-14 08:11:47 -05:00
{
2019-01-21 12:57:05 -05:00
if ( PotentialLocalizationNodeType ! = typeof ( LocalizationProvider ) & & ! PotentialLocalizationNodeType . IsAbstract & & ! PotentialLocalizationNodeType . IsInterface & & typeof ( LocalizationProvider ) . IsAssignableFrom ( PotentialLocalizationNodeType ) )
2016-01-14 08:11:47 -05:00
{
2019-01-21 12:57:05 -05:00
// Types should implement a static StaticGetLocalizationProviderId method
var Method = PotentialLocalizationNodeType . GetMethod ( "StaticGetLocalizationProviderId" ) ;
if ( Method ! = null )
2016-01-14 08:11:47 -05:00
{
2019-01-21 12:57:05 -05:00
try
{
var LocalizationProviderId = Method . Invoke ( null , null ) as string ;
CachedLocalizationProviderTypes . Add ( LocalizationProviderId , PotentialLocalizationNodeType ) ;
}
catch
{
2023-03-09 14:51:40 -05:00
Logger . LogWarning ( "Type '{Name}' threw when calling its StaticGetLocalizationProviderId method." , PotentialLocalizationNodeType . FullName ) ;
2019-01-21 12:57:05 -05:00
}
2016-01-14 08:11:47 -05:00
}
2019-01-21 12:57:05 -05:00
else
2016-01-14 08:11:47 -05:00
{
2023-03-09 14:51:40 -05:00
Logger . LogWarning ( "Type '{Name}' derives from LocalizationProvider but is missing its StaticGetLocalizationProviderId method." , PotentialLocalizationNodeType . FullName ) ;
2016-01-14 08:11:47 -05:00
}
}
}
}
}
2019-01-21 12:57:05 -05:00
Type LocalizationNodeType ;
CachedLocalizationProviderTypes . TryGetValue ( InLocalizationProviderId , out LocalizationNodeType ) ;
if ( LocalizationNodeType ! = null )
2016-01-14 08:11:47 -05:00
{
2019-01-21 12:57:05 -05:00
try
{
return Activator . CreateInstance ( LocalizationNodeType , new object [ ] { InLocalizationProviderArgs } ) as LocalizationProvider ;
}
catch ( Exception e )
{
2023-03-09 14:51:40 -05:00
Logger . LogWarning ( e , "Unable to create an instance of the type '{Type}'. {Message}" , LocalizationNodeType . FullName , e . ToString ( ) ) ;
2019-01-21 12:57:05 -05:00
}
2016-01-14 08:11:47 -05:00
}
2019-01-21 12:57:05 -05:00
else
2016-01-14 08:11:47 -05:00
{
2023-03-09 14:51:40 -05:00
Logger . LogWarning ( "Could not find a localization provider for '{Id}'" , InLocalizationProviderId ) ;
2016-01-14 08:11:47 -05:00
}
2019-01-21 12:57:05 -05:00
return null ;
2016-01-14 08:11:47 -05:00
}
2019-01-21 12:57:05 -05:00
protected string RootWorkingDirectory ;
protected string LocalizationBranchName ;
protected string RemoteFilenamePrefix ;
protected bool bUploadAllCultures ;
protected BuildCommand Command ;
protected int PendingChangeList ;
2016-01-14 08:11:47 -05:00
2019-01-21 12:57:05 -05:00
private static Dictionary < string , Type > CachedLocalizationProviderTypes ;
} ;
2016-01-14 08:11:47 -05:00
}