Detecting User’s Language via GDL

or

Sometimes you need to take the long route

A reoccurring question in Archicad’s GDLGeometric Description Language, a proprietary BASIC-dialect made by Graphisoft is how to tackle localization. While Graphisoft localizes and translates their objects before shipping Archicad (sometimes done not by GS itself but by local resellers), independent manufacturers and programmers rather keep their objects together than splitting and duplicating the code for every language they support.

A user on Architalk wanted to know if there is the possibility to get to know which language Archicad is running on.
While there is REQ("GDL_Version"), which tells us the version number of ArchicadAt least indirectly, since GDL_Version and the Archicad version number relate to each other, but are different: E.g. for Archicad 23 build 3003 the output of the request would be 2.300000., there is no dedicated command or request to get to know the language the user is using.

A Clever Idea

My solution is based on the fact that most users will have their default Archicad library loaded – and remember: those libraries are localized!

At the root of the provided library is a XML file called ARCHICAD Library.version
It looks more or less like this:

<productversion>
  <buildnumber>2800</buildnumber>
  <projectbuildnumber>4010</projectbuildnumber>
  <codename>v2019</codename>
  <versionstring>23.0.0</versionstring>
  <shortversionstring>23</shortversionstring>
  <platform>MAC32</platform>
  <gslanguage>GER</gslanguage>
  <gsprodtype>FULL</gsprodtype>
  <prefspostfix>v2019 GER 2800.4010</prefspostfix>
  <guid>{6108D34D-A54F-49CE-A83C-9B805F956D74}</guid>
  <supersedes-lib name="BIBLIOTHEKEN 20" guid="{FF6B2803-AC38-48C2-ABD6-6D56DD453444}"/>
  <supersedes-lib name="BIBLIOTHEKEN 21" guid="{7A18EB31-3044-4E99-8F54-B6CB16B6CE88}"/>
  <supersedes-lib name="BIBLIOTHEKEN 22" guid="{C46B01B7-097F-4F18-9B3D-71413F211E37}"/>
  <collapse-branches/>
</productversion>
ARCHICAD Library.version

What’s interesting here is the gslanguage part: since users normally have no access to libraries not shipped with their Archicad, we can utilize that to see what language the user expects.

The Implementation

GDL has the XML Addon which will help to traverse this XML.
(It took me about an hour to figure out how this is actually supposed to work… – the GDL warnings are useless as always.)

In the end it is rather simple. Basically just four SLOC. I will go through all of them, but if you are in a hurry you can grab the (annotated) code example at GitHub.

First we need to declare all the variables we need.

_dummy = "" ! only made so it can be ignored…
pos    = ""
nodename  = ""
nodevalue = ""
nodetype  = ""
easy stuff, right?

Then we need to open the file. In GDL that is called a “channel”. The command for that is straightforward: “OPEN”:

ch = OPEN ('xml', 'ARCHICAD Library.version', 'rl')
The first parameter is the add-on type, the second the file name, and the third is the operation mode; in this case we want the flags set to `l` locally loaded file which should be opened as `r` readonly.

Now it gets a little bit confusingAll this stuff is needed, because GDL as BASIC based language can’t really work well with structured markup like XML. If you would need more data than just from one node, you would work with loops. An example of that can be found here.. A XML file can be understood like a tree, which has a root and then keeps branching out. To traverse this hierarchy we need a device which guides us through the data jumble. This interface is provided by the NewPositionDesc command:

r = INPUT (ch, "NewPositionDesc", _dummy, pos)
`pos` will return a new position descriptor.

The INPUT instruction is used when reading XML files, you have to call it on the channel you want to readIt is totally possible to read from multiple files at the same time.. The position descriptor will yield the root of the XML if you call it for the first time.

We now have a position descriptor initialized which currently points to the root element. With this set we can finally walk through the nodes of our XML.
We do so again by using the INPUT instruction, but this time with a slightly different command:

rr = INPUT (ch, "MoveToNode FromFirstChild g* ELEM 1", pos, nodename, nodevalue, nodetype)

There are a lot of things going on in just one line so let me explain that briefly:
The command translates to “Move to the firstThe “1” in the command could be omitted. child node which starts with ‘g’”.
What might be confusing is the fact that the INPUT instruction set not only takes input parameters but also mutates them! The pos position descriptor gets fed into the command as a starting point. By the end of the command the pos variable will be returned with a new value – the descriptor now points to the found node. nodename will output “gslanguage” at this very moment.

But alas! We are not there yet! As you may have noticed nodevalue is empty. We still didn’t got the actual value since we just arrived at the node, but don’t know what’s inside. There could be more subnodes in here after all!

rrr = INPUT (ch, "MoveToNode FromFirstChild * TXT", pos, nodename, nodevalue, nodetype)
Basically the same as above, but this time we explicitely want a `TXT` value.

And there you have it!
The nodevalue will be the three letter string, GER in this case. What is still not clear to me is if gslanguage refers to the country version or the language. E.g. Germany, Switzerland, and Austria speak German – have they their own gslanguage codes? Please tell me in the comments down below if you have any information on that.It at least definitely doesn’t adhere to ISO 3166-1 alpha-3 – German would be DEU


I hope you found something valuable along the way.
Happy coding! 👋🏻💻

Update

I could get a glimpse into the Austrian libray: their gslanguage will say “AUT”. So I guess they are using their custom language version codes. Those are:
AUS, AUT, BRA, CHE, CHI, CZE, FIN, FRA, GER, GRE, HUN, INT, ITA, JPN, KOR, NED, NOR, NZE, POL, POR, RUS, SPA, SWE, TAI, TUR, UKI, USA.

Comments