2022-10-30 14:49:22 +00:00
using System.Text ;
using DataModel.Database ;
namespace Processor.Generators ;
public class DotnetBigFile : IGenerator
{
private static readonly List < string > CULTURE_CODES = new ( ) ;
private static int DEFAULT_CULTURE_INDEX = - 1 ;
2022-11-01 18:24:27 +00:00
public async Task < ProcessorResult < long > > GenerateAsync ( )
2022-10-30 14:49:22 +00:00
{
const string filename = "I18N.cs" ;
var destPath = await AppSettings . GetGeneratorDotnetDestinationPath ( ) ;
destPath = Environment . ExpandEnvironmentVariables ( destPath ) ;
2022-11-01 18:24:27 +00:00
long destBytesWritten = 0 ;
2022-10-30 14:49:22 +00:00
var pathFinal = Path . Join ( destPath , filename ) ;
var pathTemp = Path . Join ( destPath , filename + ".gen" ) ;
2022-11-01 18:24:27 +00:00
var issueFinal = string . Empty ;
try
{
if ( File . Exists ( pathTemp ) )
File . Delete ( pathTemp ) ;
}
catch ( IOException e )
{
return new ProcessorResult < long > ( 0 , false , $"Cannot delete the temporary file: '{e.Message}'. Hint: Is the ransomware protection enabled in your Windows system? If so, please make sure that the I18N Commander has write permission." ) ;
}
2022-10-30 14:49:22 +00:00
CULTURE_CODES . Clear ( ) ;
var cultures = await AppSettings . GetCultureInfos ( ) ;
foreach ( var ( code , _ ) in cultures )
CULTURE_CODES . Add ( code ) ;
DEFAULT_CULTURE_INDEX = await AppSettings . GetGeneratorDotnetDefaultCultureIndex ( ) ;
DEFAULT_CULTURE_INDEX - = 1 ; // 1-based to 0-based
try
{
await using var fileStream = new FileStream ( pathTemp , FileMode . CreateNew , FileAccess . Write , FileShare . None ) ;
await using var writer = new StreamWriter ( fileStream , Encoding . UTF8 ) ;
await writer . WriteLineAsync ( $"namespace {await AppSettings.GetGeneratorDotnetNamespace()};" ) ;
await this . CreateStaticClass ( writer , "I18N" , 0 , async ( streamWriter , indention ) = >
{
var indentionString = this . AddIndention ( indention ) ;
var buildTime = DateTime . UtcNow ;
await writer . WriteLineAsync ( $"{indentionString}public static readonly string BUILD_TIME = \" { buildTime : yyyy . MM . dd HH : mm : ss } \ ";" ) ;
await writer . WriteLineAsync ( $"{indentionString}public static readonly long BUILD_TIME_TICKS = {buildTime.Ticks};" ) ;
await writer . WriteLineAsync ( ) ;
await writer . WriteLineAsync ( $"{indentionString}private static int PREVIOUS_CULTURE = -1;" ) ;
// Go through the first layer of sections:
var sections = await SectionProcessor . LoadLayer ( 0 ) ;
foreach ( var section in sections )
await this . TransformSection ( writer , indention , section ) ;
} ) ;
}
2022-11-01 18:24:27 +00:00
catch ( IOException e )
{
// Happens, e.g. when the ransomware protection on Windows is active and
// the I18N commander is not on the exclusion list.
return new ProcessorResult < long > ( 0 , false , $"Cannot write the generator's result file: '{e.Message}'. Hint: Is the ransomware protection enabled in your Windows system? If so, please make sure that the I18N Commander has write permission." ) ;
}
2022-10-30 14:49:22 +00:00
finally
{
2022-11-01 18:24:27 +00:00
if ( File . Exists ( pathTemp ) )
2022-10-30 14:49:22 +00:00
{
2022-11-01 18:24:27 +00:00
destBytesWritten = new FileInfo ( pathTemp ) . Length ;
if ( destBytesWritten > 0 )
{
try
{
if ( File . Exists ( pathFinal ) )
File . Delete ( pathFinal ) ;
File . Move ( pathTemp , pathFinal ) ;
}
catch ( IOException e )
{
// Happens when the file is still in use by the compiler, the IDE, etc.
// Depends on the timing, this happens sometimes. We ignore it, though.
issueFinal = e . Message ;
}
}
2022-10-30 14:49:22 +00:00
}
}
2022-11-01 18:24:27 +00:00
if ( string . IsNullOrWhiteSpace ( issueFinal ) )
return new ProcessorResult < long > ( destBytesWritten , true , string . Empty ) ;
else
return new ProcessorResult < long > ( 0 , false , $"Cannot move the generator's result file to the destination: '{issueFinal}'. Hint: Is the ransomware protection enabled in your Windows system? If so, please make sure that the I18N Commander has write permission." ) ;
2022-10-30 14:49:22 +00:00
}
private string AddIndention ( int indention ) = > new string ( ' ' , indention * 3 ) ;
private async Task TransformSection ( TextWriter writer , int indention , Section section )
{
await this . CreateStaticClass ( writer , section . DataKey , indention , async ( _ , innerIndention ) = >
{
var textElements = section . TextElements ;
foreach ( var textElement in textElements )
await this . TransformTextElement ( writer , innerIndention , textElement ) ;
var childSections = await SectionProcessor . GetChildSections ( section . DataKey ) ;
foreach ( var childSection in childSections )
await this . TransformSection ( writer , innerIndention , childSection ) ;
} ) ;
}
private async Task TransformTextElement ( TextWriter writer , int indention , TextElement textElement )
{
var indentionString = this . AddIndention ( indention ) ;
var indentionPropString = this . AddIndention ( indention + 1 ) ;
var indentionPropInner1String = this . AddIndention ( indention + 2 ) ;
var indentionPropInner2String = this . AddIndention ( indention + 3 ) ;
var indentionPropInner3String = this . AddIndention ( indention + 4 ) ;
await writer . WriteLineAsync ( $"{indentionString}private static string E_{textElement.Code}_CACHE = \" \ ";" ) ;
await writer . WriteLineAsync ( $"{indentionString}public static string E_{textElement.Code}" ) ;
await writer . WriteLineAsync ( $"{indentionString}{{" ) ;
await writer . WriteLineAsync ( $"{indentionPropString}get" ) ;
await writer . WriteLineAsync ( $"{indentionPropString}{{" ) ;
await writer . WriteLineAsync ( $"{indentionPropInner1String}var currentCulture = CultureInfo.CurrentCulture.Name;" ) ;
await writer . WriteLineAsync ( $"{indentionPropInner1String}if(PREVIOUS_CULTURE == currentCulture.GetHashCode())" ) ;
await writer . WriteLineAsync ( $"{indentionPropInner2String}return E_{textElement.Code}_CACHE;" ) ;
await writer . WriteLineAsync ( $"{indentionPropInner1String}else" ) ;
await writer . WriteLineAsync ( $"{indentionPropInner1String}{{" ) ;
await writer . WriteLineAsync ( $"{indentionPropInner2String}PREVIOUS_CULTURE = currentCulture.GetHashCode();" ) ;
for ( var cultureIndex = 0 ; cultureIndex < CULTURE_CODES . Count ; cultureIndex + + )
{
if ( cultureIndex = = 0 )
await writer . WriteLineAsync ( $"{indentionPropInner2String}if (currentCulture.StartsWith(\" { CULTURE_CODES [ cultureIndex ] } \ ", StringComparison.InvariantCultureIgnoreCase))" ) ;
else
await writer . WriteLineAsync ( $"{indentionPropInner2String}else if (currentCulture.StartsWith(\" { CULTURE_CODES [ cultureIndex ] } \ ", StringComparison.InvariantCultureIgnoreCase))" ) ;
await writer . WriteLineAsync ( $"{indentionPropInner2String}{{" ) ;
var cultureTranslation = textElement . Translations . FirstOrDefault ( x = > x . Culture = = CULTURE_CODES [ cultureIndex ] ) ;
var cultureText = cultureTranslation ? . Text ? ? string . Empty ;
await writer . WriteLineAsync ( $"{indentionPropInner3String}var text = @\" { Utils . MadeVerbatimStringLiteral ( cultureText ) } \ ";" ) ;
await writer . WriteLineAsync ( $"{indentionPropInner3String}E_{textElement.Code}_CACHE = text;" ) ;
await writer . WriteLineAsync ( $"{indentionPropInner3String}return text;" ) ;
await writer . WriteLineAsync ( $"{indentionPropInner2String}}}" ) ;
}
// Add the default case:
await writer . WriteLineAsync ( $"{indentionPropInner2String}else" ) ;
await writer . WriteLineAsync ( $"{indentionPropInner2String}{{" ) ;
var defaultCultureTranslation = textElement . Translations . FirstOrDefault ( x = > x . Culture = = CULTURE_CODES [ DEFAULT_CULTURE_INDEX ] ) ;
var defaultCultureText = defaultCultureTranslation ? . Text ? ? string . Empty ;
await writer . WriteLineAsync ( $"{indentionPropInner3String}var text = @\" { Utils . MadeVerbatimStringLiteral ( defaultCultureText ) } \ ";" ) ;
await writer . WriteLineAsync ( $"{indentionPropInner3String}E_{textElement.Code}_CACHE = text;" ) ;
await writer . WriteLineAsync ( $"{indentionPropInner3String}return text;" ) ;
await writer . WriteLineAsync ( $"{indentionPropInner2String}}}" ) ;
await writer . WriteLineAsync ( $"{indentionPropInner1String}}}" ) ;
await writer . WriteLineAsync ( $"{indentionPropString}}}" ) ;
await writer . WriteLineAsync ( $"{indentionString}}}" ) ;
await writer . WriteLineAsync ( ) ;
}
private async Task CreateStaticClass ( TextWriter writer , string name , int indention , Func < TextWriter , int , Task > content )
{
var indentionString = this . AddIndention ( indention ) ;
await writer . WriteLineAsync ( indentionString ) ;
await writer . WriteLineAsync ( $"{indentionString}public static class {name}" ) ;
await writer . WriteLineAsync ( $"{indentionString}{{" ) ;
await content ( writer , indention + 1 ) ;
await writer . WriteLineAsync ( $"{indentionString}}}" ) ;
}
}