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 ) ;
2023-02-12 15:18:11 +00:00
await writer . WriteLineAsync ( "" "using System.Globalization;" "" ) ;
await writer . WriteLineAsync ( $"""namespace {await AppSettings.GetGeneratorDotnetNamespace()};""" ) ;
2022-10-30 14:49:22 +00:00
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};" ) ;
2023-02-12 15:18:11 +00:00
2022-10-30 14:49:22 +00:00
// 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 ) ;
2023-02-12 15:18:11 +00:00
var indentionInner1 = this . AddIndention ( indention + 1 ) ;
var indentionInner2 = this . AddIndention ( indention + 2 ) ;
2022-10-30 14:49:22 +00:00
2023-02-12 15:18:11 +00:00
await writer . WriteLineAsync ( $"""{indentionString}public static string E_{textElement.Code}() => E_{textElement.Code}(CultureInfo.CurrentCulture);""" ) ;
await writer . WriteLineAsync ( $"""{indentionString}public static string E_{textElement.Code}(CultureInfo culture)""" ) ;
await writer . WriteLineAsync ( $ $"""{{indentionString}}{""" ) ; // opening {
// Write the default culture's text:
var defaultCultureTranslation = textElement . Translations . FirstOrDefault ( x = > x . Culture = = CULTURE_CODES [ DEFAULT_CULTURE_INDEX ] ) ;
var defaultCultureText = defaultCultureTranslation ? . Text ? ? string . Empty ;
await this . WriteTextContent ( writer , indentionInner1 , textElement . IsMultiLine , defaultCultureText , variableName : "defaultText" ) ;
await writer . WriteLineAsync ( $"""{indentionInner1}var name = culture.Name;""" ) ;
await writer . WriteLineAsync ( $"""{indentionInner1}if(name.Length < 2)""" ) ;
await writer . WriteLineAsync ( $ $"""{{indentionInner1}}{""" ) ; // opening {
await writer . WriteLineAsync ( $"""{indentionInner2}return defaultText;""" ) ;
await writer . WriteLineAsync ( $ $"""{{indentionInner1}}}""" ) ; // closing }
2022-10-30 14:49:22 +00:00
for ( var cultureIndex = 0 ; cultureIndex < CULTURE_CODES . Count ; cultureIndex + + )
{
2023-02-12 15:18:11 +00:00
await writer . WriteLineAsync ( $"""{indentionInner1}if ({this.CreateIf(CULTURE_CODES[cultureIndex])})""" ) ;
await writer . WriteLineAsync ( $ $"""{{indentionInner1}}{""" ) ; // opening {
2022-10-30 14:49:22 +00:00
2023-02-12 15:18:11 +00:00
if ( cultureIndex = = DEFAULT_CULTURE_INDEX )
await writer . WriteLineAsync ( $"""{indentionInner2}return defaultText;""" ) ;
else
{
var cultureTranslation = textElement . Translations . FirstOrDefault ( x = > x . Culture = = CULTURE_CODES [ cultureIndex ] ) ;
var cultureText = cultureTranslation ? . Text ? ? string . Empty ;
await this . WriteTextContent ( writer , indentionInner2 , textElement . IsMultiLine , cultureText ) ;
await writer . WriteLineAsync ( $"""{indentionInner2}return text;""" ) ;
}
await writer . WriteLineAsync ( $ $"""{{indentionInner1}}}""" ) ; // closing }
2022-10-30 14:49:22 +00:00
}
// Add the default case:
2023-02-12 15:18:11 +00:00
await writer . WriteLineAsync ( $"""{indentionInner1}return defaultText;""" ) ;
await writer . WriteLineAsync ( $ $"""{{indentionString}}}""" ) ; // closing }
2022-10-30 14:49:22 +00:00
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}}}" ) ;
}
2023-02-12 15:18:11 +00:00
private async Task WriteTextContent ( TextWriter writer , string indention , bool isMultiline , string content , string variableName = "text" )
{
if ( isMultiline )
{
await writer . WriteLineAsync ( $"""""""" "
{ indention } const string { variableName } = "" "" "" ""
"" "" "" "" ");
await writer . WriteLineAsync ( content ) ;
await writer . WriteLineAsync ( $"""""""" "
"" "" "" "" ;
"" "" "" "" ");
}
else
await writer . WriteLineAsync ( $"""""""""{indention}const string {variableName} = """"""""{content}"""""""";""""""""" ) ;
}
private string CreateIf ( string cultureCode )
{
if ( string . IsNullOrWhiteSpace ( cultureCode ) )
return "false" ;
var sb = new StringBuilder ( ) ;
var len = cultureCode . Length ;
if ( len > 2 )
sb . Append ( $"""name.Length >= {len} && """ ) ;
for ( var i = 0 ; i < cultureCode . Length ; i + + )
{
sb . Append ( $"""name[{i}] is '{cultureCode[i]}'""" ) ;
// When this is not the last character, we need to add " && ":
if ( i < cultureCode . Length - 1 )
sb . Append ( " && " ) ;
}
return sb . ToString ( ) ;
}
2022-10-30 14:49:22 +00:00
}