Text Properties in EK9

If you are developing a small application in just a single spoken language; then the use of text properties might not be necessary.

But for applications with large amounts of text or text in multiple languages; using the EK9 text construct might be a good idea.

Having an entire construct just to hold a number of text 'Strings' might seem a little excessive to some developers. After all; it is possible just to put them in the code, or pull text out of properties files, or a CMS or even a database. All of these approach can work. But EK9 provides a built-in alternative (with compiler and type support).

Benefits of the Text construct

Example

A simple example of how the text construct can be used is shown below.

The CheckTextAccess program and Person record are just used to drive the example. There are two main text blocks - one of "en_GB" (English - specifically British English) and the other for "de" (Deutsch).

Within the text blocks there are a number of text declarations (which are a little like classes). There are WelcomePageText and LanguageValidator definitions declared for both languages. It is possible to define a declaration for just one language if needs be.

These blocks have what look like methods on them (the () is optional). These methods can have input parameters if required. They then just consist of a single String.

The String can either be a normal simple String " ... ", or an interpolated String ` ... ${...} ...`. It is possible for the String to roll over a number of lines if needed and the formatting will be retained.

There is an important point to be made here; if a declaration is made for multiple languages that has the same name then all the methods must be present on both declarations (the compiler checks this). It's almost like the compiler uses the fact the declarations have the same name to build a 'supertype' and then checks that all declarations using that name but with different languages implements all the methods.

This latter point is borne of experience of working with 'property files'. It is very easy to add or modify properties for one language but forget some others. Typically, this is only picked up at runtime. With the EK9 language the compiler helps here by checking corresponding methods.

So EK9 mandates the same methods (and parameter signatures) on all declarations with the same name.

#!ek9
defines module introduction

  defines program

    CheckTextAccess
      stdout <- Stdout()

      lang <- "en_GB"
      me <- Person("Steve", "Limb")
      englishWelcome <- WelcomePageText(lang)
      stdout.println(englishWelcome.mainWelcome())
      stdout.println(englishWelcome.namedWelcome(me))

      validator <- LanguageValidator(lang)
      stdout.println(validator.valueTooShort("Some Long Input"))

      deutschWelcome <- WelcomePageText("de")
      stdout.println(deutschWelcome.mainWelcome())
      stdout.println(deutschWelcome.namedWelcome(me))

      nonSuchWelcome <- WelcomePageText("none")
      stdout.println(nonSuchWelcome.mainWelcome())
      stdout.println(nonSuchWelcome.namedWelcome(me))

  defines record
    Person
      firstName String: String()
      lastName String: String()

      Person()
        ->
          firstName String
          lastName String
        assert firstName? and lastName?

        this.firstName :=: firstName
        this.lastName :=: lastName

      operator $ as pure
        <- rtn String: `${firstName} ${lastName}`

  defines text for "en_GB"

    WelcomePageText

      namedWelcome()
        -> person Person
        `Welcome ${person.firstName}`

      mainWelcome()
        "The main difference in processing html if you want to use hardwired content like this.
You must put it all in quotes.
As you can see above\nwith welcomeMessage, EK9 will look for variable names,
but anything in double quotes check tab[\t] is a literal.
In general you would probably use the 'text' mechanisms described in the section before this."

      endWelcome()
        `End Message.`

    LanguageValidator
      valueTooShort()
        -> input as String
        //Escape the $ with \$ as it is used for interpolation
        `The value:
\$ '${input}'
you entered is too short.
This can be multi-lined`

      valueTooLong
        -> input as String
        `The value ${input} you entered is too long`

      unknownLanguage
        ->
          input as String
          constraint as String
        `The value ${input} is not one of ${constraint}`

  defines text for "de"

    WelcomePageText
      namedWelcome()
        -> person Person
        `Willkommen ${person.firstName}`

      mainWelcome()
        "Der Hauptunterschied bei der Verarbeitung von HTML, wenn Sie fest verdrahteten Inhalt wie diesen verwenden möchten.
Sie müssen alles in Anführungszeichen setzen.
Wie Sie oben mit welcomeMessage sehen können, sucht EK9 nach Variablennamen.
aber alles in doppelten Anführungszeichen ist ein Literal.
Im Allgemeinen würden Sie wahrscheinlich die im vorherigen Abschnitt beschriebenen 'Text'-Mechanismen verwenden."

      endWelcome()
        "End Message."

    LanguageValidator
      valueTooShort()
        -> input as String
        `Der eingegebene Wert ${input} ist zu kurz`

      valueTooLong
        -> input as String
        `Der von Ihnen eingegebene Wert ${input} ist zu lang`

      unknownLanguage
        ->
          input as String
          constraint as String
        `Der Wert ${input} gehört nicht zu ${constraint}`
//EOF

The above example is designed to show a mix of fixed static text, interpolated text and also use of special characters and escape sequences.

The program produces the following output:

The main difference in processing html if you want to use hardwired content like this.
You must put it all in quotes.
As you can see above
with welcomeMessage, EK9 will look for variable names,
but anything in double quotes check tab[	] is a literal.
In general you would probably use the 'text' mechanisms described in the section before this.
Welcome Steve
The value:
$ 'Some Long Input'
you entered is too short.
This can be multi-lined
Der Hauptunterschied bei der Verarbeitung von HTML, wenn Sie fest verdrahteten Inhalt wie diesen verwenden möchten.
Sie müssen alles in Anführungszeichen setzen.
Wie Sie oben mit welcomeMessage sehen können, sucht EK9 nach Variablennamen.
aber alles in doppelten Anführungszeichen ist ein Literal.
Im Allgemeinen würden Sie wahrscheinlich die im vorherigen Abschnitt beschriebenen 'Text'-Mechanismen verwenden.
Willkommen Steve
        

Summary

As is evident from the example above the main program CheckTextAccess is very simple and clean. It is not cluttered with formatted text. It is also very simple to select the specific set of language resources needed (and exception is thrown at runtime if the language resource does not exist).

This comes back to SOLID and specifically a separation of concerns.

The methods can accept parameters of any type and any number. Those parameters can then be used in formatted interpolated Strings, this enables any resultant String to be created.

Once of the most important things with this text construct approach is the ability to quickly and easily unit test all the output text that might be used with an application in isolation.

By extracting the text to separate constructs testing is made much easier and real focus can be given to the formatting of text output (not a trivial task for html emails for example).

If you had a very large amount of text it would be simple to store them in separate source files but locate them all in the same module. Likewise, if you needed to support a large number of spoken languages, storing each set of text declarations in a separate file would make sense.

The EK9 compiler will still check all methods exist across all the languages you plan to support; even if they are stored over several files.

Next Steps

The next set of construct sections focus much more on higher level structural architecture and software design; they take composition much further by introducing on components, dependency injection and finally web services which is largest and final architectural construct in EK9.