9.2 The resource string file

When a unit is compiled that contains a resourcestring section, the compiler does 2 things:

  1. It generates a table that contains the value of the strings as declared in the sources.

  2. It generates a resource string file that contains the names of all strings, together with their declared values.

This approach has 2 advantages: first of all, the value of the string is always present in the program. If the programmer doesn’t care to translate the strings, the default values are always present in the binary. This also avoids having to provide a file containing the strings. Secondly, having all strings together in a compiler generated file ensures that all strings are together (you can have multiple resourcestring sections in 1 unit or program) and having this file in a fixed format, allows the programmer to choose his way of internationalization.

For each unit that is compiled and that contains a resourcestring section, the compiler generates a file that has the name of the unit, and an extension .rsj. The format of this file is a JSON file (in codepage UTF8), structured as follows (formatting added for clarity):

{ "version":1,
  "strings":[
    {"hash":53831826,
     "name":"custapp.serrinvalidoption",
     "sourcebytes":[73,110,118,97,108,105,100,32,111,112,116,105,
                    111,110,32,97,116,32,112,111,115,105,116,105,
                    111,110,32,37,100,58,32,34, 37,115,37],
      "value":"Invalid option at position %d: \"%s\""
   }
  ]
}

The global JSON object contains 2 elements: a version number and an array called strings. The array contains an element (a JSON object) for every resource string in the unit. This JSON object contains the following properties:

  1. hash: a has value of the string, for fast lookup.

  2. name: the fully qualified name of the sresource string, in all lowercase letters. The name is composed of the unit name, a dot and the resource string identifier.

  3. sourcebytes: The sourcebytes are the bytes that compose the string as they were read from the source file.

  4. value the value of the resource string, in UTF8.

If the unit contains no resourcestring section, no file is generated.

For example, the following unit:

unit rsdemo;

{$mode delphi}
{$H+}

interface

resourcestring

  First = 'First';
  Second = 'A Second very long string that should cover more than 1 line';


implementation

end.

Will result in the following resource string file:

{
  "version":1,
  "strings":[
    {"hash":5048740,
     "name":"rsdemo.first",
      "sourcebytes":[70,105,114,115,116],
      "value":
    "First"
    },
    {"hash":171989989,
     "name":"rsdemo.second",
     "sourcebytes":[65,32,83,101,99,111,110,100,32,
                    118,101,114,121,32,108,111,110,
                    103,32,115,116,114,105,110,103,
                    32,116,104,97,116,32,115,104,
                    111,117,108,100,32,99,111,118,
                    101,114,32,109,111,114,101,32,
                    116,104,97,110,32,49,32,108,
                    105,110,101],
     "value":"A Second very long string that
              should cover more than 1 line"}
  ]
}

The hash value is calculated with the function Hash. It is present in the objpas unit. The value is the same value that the GNU gettext mechanism uses. It is in no way unique, and can only be used to speed up searches.

The rstconv utility that comes with the Free Pascal compiler allows manipulation of these resource string files. At the moment, it can only be used to make a .po file that can be fed to the GNU msgfmt program. If someone wishes to have another format (Win32 resource files spring to mind), one can enhance the rstconv program so it can generate other types of files as well. GNU gettext was chosen because it is available on all platforms, and is already widely used in the Unix and free software community. Since the Free Pascal team doesn’t want to restrict the use of resource strings, the .rst format was chosen to provide a neutral method, not restricted to any tool.

If you use resource strings in your units, and you want people to be able to translate the strings, you must provide the resource string file. Currently, there is no way to extract them from the unit file, though this is in principle possible. It is not required to do this, the program can be compiled without it, but then the translation of the strings isn’t possible.