Format of langfiles
OpenTTD Development Documentation
External Links

OpenTTD GitHub
Contributing to OpenTTD - guidelines
OpenTTD Doxygen

General Reference

Coding style
Compiling OpenTTD
Add a setting
Add a squirrel function
Understanding the SaveGame handler
Bumping the savegame version
Doing an OpenTTD release

Language and Strings

Manual of style
Format of langfiles
Using OpenTTD strings
List of special strings

Window System

Using the window system
Colour codes that exist in OpenTTD
Adding a text box
Understanding the widget focus system
GUI style guide


The OpenTTD TCP protocol
The OpenTTD UDP protocol
Debugging desyncs
Server Admin Port development

Ingame Console

The console window
Console commands
Console variables
Using console scripting
Adding functions/commands to the console
Adding variables to the console
Console development history

Content APIs (modding frameworks)

Graphics and similar (NewGRF)
AI framework (NoAI)
GameScript framework (NoGO)
Social Integration

Other Reference

Map array (landscape grid)
Train acceleration
Sound IDs



Note that this is a guide for development. For simple translation of OpenTTD to alternative languages, the web translator is used.

Compiling lang files

/File/en/Outdated content.png
Out of Date
This article or section is outdated. Some of its content may no longer be accurate due to changes in the latest release. Please update this article.
Section contains a link to a page with outdated information (a broken link to download stren)

The OpenTTD GitHub docs contain a guide to compiling lang files.

General layout

Each entry of the langfile consists of exactly one line.

An entry is either a comment, a pragma or a translation.

If you use the web translator tool, you only see translations.

The encoding is UTF-8.


Comments start either with one or more than two hash signs (#) or with a semicolon (;). Empty lines are ignored too.

# Ignore
#### Ignore this
;and this too


Pragmas start with two hash signs (#). The following table lists all available pragmas:

Name Function
name name Name of the language in English
ownname name Name of the language in the language itself
isocode code ISO code for the language (eg. de)
plural number Type of the plural forms (for a list of codes see below)
gender up to 8 gender names defines the list of allowed genders
case up to 50 case names defines the list of available cases
textdir ltr or rtl defines the text direction (ltr stands for "left-to-right" whilst rtl stands for "right-to-left", i.e. Hebrew or Arabic)
digitsep symbol separator of digits for non-currency values, also known as "thousand separator"
digitsepcur symbol separator of digits for currency values
decimalsep symbol separator of decimals
winlangid hexnumber the identifier of the language as defined by Microsoft Windows®
grflangid hexnumber the identifier of the language as used for the GRF
id hexnumber Next string id starts at hexnumber

List of plural types

The table below states the allowed code values on how a plural is being formed:

Code Value Description
Used for
0 Two forms, singular used for one only
Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish, Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto
1 Only one form
Hungarian, Japanese, Turkish
2 Two forms, singular used for zero and one
French, Brazilian Portuguese
3 Three forms, special case for zero
4 Three forms, special case for one and two
Gaelige (Irish)
5 Three forms, special case for numbers ending in 1[2-9]
6 Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4]
Croatian, Czech, Russian, Slovak, Ukrainian
7 Three forms, special case for one and numbers ending in 2, 3, or 4, except those ending in 1[2-4]
8 Four forms, special case for one and all numbers ending in 02, 03, or 04
11 Two forms, special case for all ending 0, 1, 3, 6, 7, 8. This is not an actual plural but to implement korean postpositions


The standard language file english.txt starts with the following pragmas:

##name English (UK)
##ownname English (UK)
##isocode en_GB
##plural 0
##textdir ltr
##id 0x0000


Translations consist of a key and a translation. They are separated by a colon (:).


The key can only contain uppercase letters, numbers and the underscore (_). Each key starts with "STR_" followed by one or more well describing words.



Using curly braces {}, special commands can be inserted into the translations, which are substituted either by strgen or while the string is drawn on the screen. For a full list of commands is available at Special Strings. Besides




it is recommended to leave those special strings untouched by default. The special commands may substitute values or other strings at where the Special Strings are placed. Translators may have influence on the sequence of these replacements to allow a fluent language.

Changing word order

Parameter replacements can be made swappable too. This will allow one parameter that is usually at position 0 (as in : the first one ) in the translated string to be used in fact at position 1, thus swapping place with no 1.


In English, the string reads as "{BLACK}{BIGFONT}{STRING} production at {INDUSTRY} increases {COMMA}%!"

In Finnish, same string is now "{BLACK}{BIGFONT}{1:INDUSTRY} tuottaa {0:STRING} {2:COMMA}{NBSP}% entistä enemmän!"

To Do
Finish and correct this


After each key, there can be a custom suffix case separated by the period (.). The case must be defined first at the beginning of the file by ##case pragma.

In the following example from the Czech language file, you can see how to define the cases. The Czech language has 7 cases and there is an extra "case" for capitalizing cargo name in the Subsidies dialog.

##case nom gen dat acc voc loc ins big
STR_0011_MAIL                      :pošta
STR_0011_MAIL.big                  :Pošta
STR_0011_MAIL.gen                  :pošty

The generic usage of cases is to append a period and the case name to the STRING command. In the paragraph "Dotace dopravy {STRING.gen} z{NBSP}{STRING} do {STRING} nebude dále nabízena." a genitive case is necessary.

STR_202E_OFFER_OF_SUBSIDY_EXPIRED  :{BLACK}{BIGFONT}Nabídka dotace přepravy vypršela:{}{}Dotace dopravy {STRING.gen} z{NBSP}{STRING} do {STRING} nebude dále nabízena.
STR_2027_FROM_TO                   :{ORANGE}{STRING.big} z {STRING} do {STRING}

Plural form


In most languages singular and plural forms are a bit different. Every word may be divided into two parts - one part does not change in both singular and plural form, but the second part differs in singular and plural. Let's call them core and suffix.

Let's take basic example in English language, which is basic because it has two forms: singular and plural.

There is "1 train", but there are "2 trains".

Now, let's divide this word into part that does not change and part that changes:

Writing the string

As I said before, there are two forms in English language.

The basic structure for plural form in English is

core{P suffix1 suffix2}

where suffix1 is suffix for signular and suffix2 is suffix for plural.

Keep in mind, that plural forms work only if there is proper parameter in the string.

{COMMA} and {NUM}, along with other numeric params work well in determining plural form.

Let's make a string that displays number of lamps in the room. Form of "lamp" would depend on supplied amount via {NUM} parameter.


STR_SENTENCE : I have {NUM} lamp{P "" s}

Do you see the core? Yes, it is the word lamp.

Later you see {P. This is the indicator that suffixes will come next.

"" means there is no suffix. OpenTTD needs to know that - If there is no suffix, just write two quotation marks. So this is the first suffix, which will be used when {NUM} is equal to 1

s is the second suffix. This one will be displayed when {NUM} is bigger than 1.

Let's proceed to more advanced plural forms. Let's take mouse. Its plural form is mice.

First of all, imagine the sentence with different parameters.

When you are ready, you can write the string.

STR_SENTENCE : Mum, there {P 0 is are} {NUM} m{P ouse ice} in the room!

As you may have noticed, the first {P contains an extra number before the suffixes. This is used to specify which parameter should be used to determine the plural form. When no number is given, the previous parameter is used, but in this case there is no previous parameter, that's why we need to specify it.

To Do
check if it is not wrong

Mind that the singluar (1) is special in this plural definition. The plural form is used for all numbers >1 but also for 0. (Mum, there are 0 mice in the room).

String as number

If the argument that affects a plural form is given as {STRING} then you need to use a special parameter for {P:

Flat area around industries: {ORANGE}{STRING} tile{P 0:1 "" s}

OpenTTD usage

Now you understand basics of plural forms. Let's take some example from English translation.

STR_QUANTITY_LIVESTOCK : {COMMA} item{P "" s} of livestock

This text is being displayed at stations when there is livestock cargo awaiting.

As you can see, {COMMA} parameter is given. Thanks to that parameter, we can change form of item. Let's see how the string would change when we change supplied parameter.

Now let's take a look at string without given parameter.


No plural form may be applied here. Wagon{P "" s} will not work here.

Why? Because there is no parameter given.

You can just leave this string as it is.

Other plural types

Find your language on List of plural-types table below. Languages are being groupped depending on behaviour of words with different amounts.

Suffixes are being ordered ascending, with any other number at end:

Let's take Polish language and invent some dummy string

STR_CARS : {NUM} aut{P o a ""}

Now take a look at description above, and guess how would the string look for {NUM} equal to 1, 2, 5, 13, 23, 38?



Some languages feature genders. Each noun (like factory, calculator, dragon) has its gender. Adjectives (green, new, beautiful) and sometimes verbs (to fall, to eat) are being affected by gender.

First of all, think of your language's gender. Then, open the Web Translator 2, go to "Manage" page of your language and check the dropdown list of genders. If there are no genders yet, hit "+" button and supply short forms of your genders (m f n for male female neutral is good).

When you've done this, think of strings in OpenTTD that may require genders. News report that new industry is being founded is good, because industry is a noun and some words in the string should change depending on gender.

Writing the string

To set string's gender, insert {G=*} tag before first word of the string, where * is name of the gender you sent before.

In the string that may change depending on genders, use {G suffix1 suffix2 suffix3} structure, where each suffix corresponds to the right gender (gender order is in the "Manage" section of your language, in the dropdown list)


I'll use The Latin language in examples, because it is well-known, and of course, uses genders.

Latin language has three genders, we will call them m, f and n.

Let's guess some nouns we will use in examples.

Let's take some adjective and find its core and suffixes:

magnus, magna, magnum - large (male, female, neutral)

As you can see, magn is the core, and suffixes are us, a and um respectively for male, female and neutral gender.

And this is how would the example string work:

STR_WELL : {G=m}Puteus
STR_FACTORY : {G=f}Officina
STR_SQUARE : {G=n}Forum
STR_IS_BIG : {STRING} magn{G us a um} est

Do you imagine how will the result look like? Here is the answer:

Again, as with plural form, if there is no suffix, write "". Use always as many suffixes as there are genders.

To Do
How about the order of the suffixes? Do you have to use the same order as defined in the pragma?

Advanced use

{G...} tag bases on gender of {STRING} after the tag. However, if you need to change suffix of a word which is after {STRING} (before tag), you have to write ID of string you want to retrieve gender from. This may sound clumsy, so let's take a look at example:

{BLACK}{BIGFONT}Now{G y a e} {STRING} został{G "" a o} posadzon{G y a e} blisko {TOWN}!

Second and third {G...} will not work, because there is no {STRING} after them to get gender from.

We want to retrieve gender from first (and the only one) {STRING} tag. First tag has ID=0, second tag has ID=1 and so on. Here is how to do that:

{BLACK}{BIGFONT}Now{G y a e} {STRING} został{G 0 "" a o} posadzon{G 0 y a e} blisko {TOWN}!

Adding IDs resolved the problem. The string works as expected.

What if there are more {STRING}s? (

To Do
I'm not sure, please verify this

) In the following example we use two genders: male and female

Mis{G ter s} {STRING} is shocked by h{G 0 is er} grand{G 2 son daughter} who flamed mis{G ter s} {STRING} yesterday. The bad {G boy girl}'s name is {STRING}

Now I'll explain why some {G...}'s have numbers and other do not:

To Do
this section may be clumsy, feel free to improve it