Abstract - Mightyfrong/gallifreyan-translation-helper GitHub Wiki

The process of turning some text into Gallifreyan essentially consists of 3 steps:

  1. Parsing - input is broken up into words and each word into symbols, such as consonants, vowels, or punctuation.
  2. Translation - consecutive symbols are grouped into glyphs depending on the system's particular stacking rules.
  3. Rendering - outline and decoration info are looked up for each glyph and drawn on the canvas.

Parsing

This procedure is encapsulated in the GallifreyanParser class. Each system has to provide some sort of character map relating a string of symbols to some kind of drawing instructions or data. As the translator has evolved organically, only TARDIS Console and Doctors's Cot currently make use of this class.

The purpose of this is to split the input into words and then group together any letters which can be represented by one symbol.

In TARDIS Console, these are the consonants: CH, NG, QU, SH, TH, PH.

In Doctor's Cot, they are the consonants: ts, st, ks, fi; and the vowels: ou & ai.

Each system's parser is initialised with the line:

const parser = new GallifreyanParser(letterMap);

where letterMap is an instance of Map with the keys being the afore-mentioned letter groupings and the values being rendering data for that grouping.

One then simply feeds it the desired input text:

const result = parser.parseWords(input);

The result object represents the outcome of the parsing and has 2 properties:

  1. error: has value null unless unrecognised characters encountered, in which case it's a String relating the problem to the user.
  2. output: an array of words, which are, in turn, arrays of "letters".

In Console, all "letters" are represented by the TARDISConsonant & TARDISVowel classes which extend TARDISLetter:

export class TardisLetter{
  constructor(str, vow){
    this.toString = str;
    this.isVowel = vow;
  }
}

In Cot, due to its phonetic nature, the so-called PhoneticUnit class is used.

Translation

Gallifreyan writing systems aren't really alphabets - they don't write "letters" separately the way European languages do. So now we come to the translation step, which stacks these "letters" into "glyphs" according to each system's particular stacking rules, which are generally based on whether a "letter" is a consonant (C) or vowel (V).

This happens in the line:

const translation = result.output.map(translateWord);

where translateWord is a system-specific function which reduces an array of "letters" to a (usually smaller) array of "glyphs".

In Console, each "glyph" is represented by a 1 or 2 element array which can be either V, C, or CV. VC is written as 2 separate "glyphs".

In Cot, the possible combinations are: V, C, VC, CV, CC, CCV.

Rendering

Finally, this is where the canvas rendering context gets involved. As translation is a 2D array of "glyphs", we iterate through it with a pair of nested calls to forEach, with each system's particular drawing function in the middle of it.

For example, Console looks like this:

	translation.forEach(words => {
		words.forEach(letters =>
			tardisDraw(ctx, ...letters)
		);
		ctx.translate(glyphSize, 0);
	});

Words are spaced out by translating the canvas context by glyphSize.

Line breaks are dealt with by tardisDraw, which accepts the 1 or 2 "letters" forming each "glyph" as arguments.

The lower level drawing details are handled by the SVGRenderingContext, which we are in the process of migrating to from <canvas>.

⚠️ **GitHub.com Fallback** ⚠️