Frontend Localization

Many tutorials may be found when coming to localize a website. However the best I found is undoubtedly the document written by the creator of TYPO3, namely Kasper Skårhøj:

Anyway, here is a brief summary of what should be done…

Beware if you use TemplaVoilà: make sure extension static_info_tables is loaded, otherwise you won’t see any translation tab in module Web > Page.

Default Language

TYPO3 store the default language content with sys_language_uid = 0. The default language in itself is fully arbitrary but it’s a bit more user-friendly to define its name and flag in the backend. This is done in the pageTS of the root page of your site:

	# Default language
mod.SHARED {
	defaultLanguageFlag = gb.gif
	defaultLanguageLabel = English
	# Translation must be bound 1-1 to the default content
mod.web_layout.defLangBinding = 1

Frontend Rendering

In order to properly render content to frontend, following TypoScript code should be placed in your template. I assume here that the website is using UTF-8 encoding:

	# English as default language
config {
	sys_language_uid = 0
	language = en
	locale_all = en_GB
page {
	config.htmlTag_langKey = en
	meta.language = en

There is something worth being aware of in previous code. Value of locale_all is related to locales installed on your server.

Use following commande, with Linux, to get the list of available locales:

# locale -a

You want another locale? Simply edit file /etc/locale.gen:

en_US.UTF-8 UTF-8
fr_CH.UTF-8 UTF-8
de_CH.UTF-8 UTF-8
fr_CH ISO-8859-1

and execute following command to actually regenerate them:

# locale-gen
Generating locales (this might take a while)…
en_US.UTF-8… done
fr_CH.UTF-8… done
de_CH.UTF-8… done
fr_CH.ISO-8859-1… done
Generation complete.

Other Language Support

If you wish to translate your website, you just have to create as many as additional languages as you want using Web > List and by adding records of type sys_language. Keep a track from generated id, they will be useful to map language to sys_language_uid in Frontend.

[globalVar = GP:L=1]
	config {
		sys_language_uid = 1
		language = de
		locale_all = de_CH.utf8
	page {
		config.htmlTag_langKey = de
		meta.language = de
[globalVar = GP:L=2]
	config {
		sys_language_uid = 2
		language = fr
		locale_all = fr_CH.utf8
	page {
		config.htmlTag_langKey = fr
		meta.language = fr
config.linkVars = L
	# Best practice
config.sys_language_mode = content_fallback
	# Translation must be bound 1-1 to the default content
config.sys_language_overlay = 1

Language Selection (example)

lib.links.languages = HMENU
lib.links.languages {
	special = language
	special.value = 1,0,2,3
	special.normalWhenNoLanguage = 0
	1 = TMENU
	1 {
		noBlur = 1
		NO = 1
		NO {
			allWrap = <li>|</li>
			stdWrap.setCurrent = DE || EN || FR || IT
			stdWrap.current = 1
			ATagTitle (
				Diese Seite auf Deutsch zeigen  ||
				Show this page in English       ||
				Afficher cette page en français ||
				Visualizza questa pagina in italiano
			ATagParams (
				lang="de" xml:lang="de" ||
				lang="en" xml:lang="en" ||
				lang="fr" xml:lang="fr" ||
				lang="it" xml:lang="it"
		ACT < .NO
		ACT {
			stdWrap.setCurrent (
				<span class="current">DE</span> ||
				<span class="current">EN</span> ||
				<span class="current">FR</span> ||
				<span class="current">IT</span>
			doNotLinkIt = 1
			# Non-translated pages should be "active" anyway

Flexible Content Element

If you wish to be able to translate and localize fields of a flexible content element, you have to modify its XML structure (at the beginning of the definition):

	<meta type="array">

From now on, whenever you edit such a content block, you will be able to translate its field contents. Would a field be left empty, the master content would be automatically used instead: