inno-setup

Can I use .isl files for the messages with preprocessor directives in Inno Setup?


I have defined a variable:

#define AppVersion "5.0"

There's a lot of standard messages from the Default.isl file overridden in the `[Messages] section of my script. Here is an example:

[Messages]
en.WelcomeLabel1=Welcome to [name] {#AppVersion} Setup program. This program will install [name] {#AppVersion} on your computer.
en.SelectDirDesc=Where should [name] {#AppVersion} be installed?
en.SelectDirLabel3=Setup will install [name] {#AppVersion} into the following folder.

I don't like the fact that all those messages reside in my script and I would like to transfer them to the corresponding .isl file. The problem is that I can't use {#AppVersion} inside the .isl file as it is interpreted as simple text. Is there a way to override those messages in the .isl file taking into account that they contain {#AppVersion}?


Solution


  • If you need to inject some custom piece of information, you can preprocess .isl files like this:

    #define Token1 "value1"
    #define Token2 "value2"
    
    #define PreprocessLanguage(Path) \
      Local[0] = GetEnv("TEMP") + "\" + ExtractFileName(Path), \
      Local[1] = \
        "-ExecutionPolicy Bypass -Command """ + \
        "$contents = Get-Content '" + CompilerPath + "\" + Path + "'; " + \
        "$contents = $contents -replace '[token1]', '" + Token1 +"'; " + \
        "$contents = $contents -replace '[token2]', '" + Token2 +"'; " + \
        "Set-Content -Path '" + Local[0] + "' -Value $contents;" + \
        """", \
      Exec("powershell.exe", Local[1], , , SW_HIDE), \
      Local[0]
    
    [Languages]
    Name: "en"; MessagesFile: {#PreprocessLanguage("Default.isl")}
    Name: "nl"; MessagesFile: {#PreprocessLanguage("Languages\Dutch.isl")}
    

    The above example replaces all occurrences of [token1] and [token2] with values of Token1 and Token2 preprocessor variables.


    Theoretically, it is possible to implement this fully in the preprocessor without invoking PowerShell, with use of FileOpen, FileRead, StringChange, and SaveStringToFile functions.

    #define Token1 "value1"
    #define Token2 "value2"
    
    #define PreprocessLanguageLines(Handle, OutPath) \
        !FileEof(Handle) ? \
          Local[0] = FileRead(Handle), \
          Local[0] = StringChange(Local[0], "[token1]", Token1), \
          Local[0] = StringChange(Local[0], "[token1]", Token2), \
          SaveStringToFile(OutPath, Local[0] + NewLine, 1, 0), \
          PreprocessLanguageLines(Handle, OutPath) \
        : ""
    
    #define PreprocessLanguage(Path) \
      Local[0] = GetEnv("TEMP") + "\" + ExtractFileName(Path), \
      SaveStringToFile(Local[0], "", 0, 0), \
      Local[1] = FileOpen(CompilerPath + "\" + Path), \
      PreprocessLanguageLines(Local[1], Local[0]), \
      FileClose(Local[1]), \
      Local[0]
    

    But with the straightforward functional approach, you will hit recursion limit of the preprocessor as the language files have too many lines. It can get solved by reading multiple lines per recursion, but that's a hack.

    With use of the #sub, it should work. But it's a mess.