docassemble allows you to write a single interview that asks questions differently depending on the user’s language and locale. It also allows Unicode to be used in user-facing text, user input, and documents. With these features, docassemble should be fully usable in languages other than English.
The value of
locale must be a locale name without the language
prefix, such as
DE.utf8. Any locale you use must be
installed in the operating system of the server.
other os locales configuration directive for information
about how to install locales in the operating system of your server.
By default, only the
en_US.UTF-8 UTF-8 locale (the locale for the
United States) is installed, so you will have problems if you try to
use other locales in your interviews.
Within interviews, the functions
set_locale() will change the active language, locale, and dialect.
(The dialect is relevant only for the text-to-speech feature, which is
controlled by the special variable
If you write functions that need to know the current language or
locale, use the
get_locale() function from
docassemble.base.util module. Also note that there is a
get_dialect() for retrieving the dialect.
The language and locale settings have the following effects:
- If you have a
translationsblock in your interview, then whenever docassemble processes a phrase (text that you can mark up with Mako templating), it will use the appropriate translation of that phrase if a translation for the phrase is present in one of the Excel files referenced in the
translationsblock. For more information about creating these Excel files, see the documentation for the Download an interview phrase translation file utility.
- Built-in words and phrases from the “core” docassemble code will
be translated into the active language. Whenever docassemble
prints such a word or phrase, it calls the
word()function from the
word('Login')will look up the word
Loginin a translation table. If the
word()function finds the word
Loginin the translation table for the active language, it will return the translated value. If it does not find a translation, it will return
Login. For more information about how
word()works, see functions. For information on how to define translations for a server, see the
wordsdirective in the configuration. For information on downloading a complete list of these phrases so that you can translate them into another language, see the documentation for the utility called Translate system phrases into another language.
- When docassemble looks for a
codeblock that defines a variable, it first tries
codeblocks for which the
languagemodifier is set to the active language (either explicitly or by operation of the
default language). If docassemble does not find any such
codeblocks, it looks for ones that do not have
languagemodifier set. This means that if your interview only uses one language, you do not need to worry about setting the
languagemodifier. If you are using the
translationsblock to translate all of the phrases in your interview, you probably will not need to use the
questionblocks, but you will need to use it on your
sectionsblock if you have one.
- Some functions have language-specific responses, such as
docassemble.base.utilmodule, which returns today’s date in a readable format such as “October 31, 2015” (for language
en) or “31 octobre 2015” (for language
fr). However, not all languages are supported by the
babel.datespackage; you may need to fall back to a different language. To configure how this works, set the
babel dates mapdirective in the Configuration.
- When docassemble highlights
termsin a question (see initial blocks), it will only highlight words specified in
termsblocks for which the
languageof the term matches the language of the question. Or, if the question does not have the
languagemodifier set, docassemble will look for a
termsblock that does not have
- When docassemble displays
interview helptext, it will only display the content of
interview helpblocks for which the
languagemodifier is the same as the language of the question. Or, if the question does not have the
languagemodifier set, docassemble will look for an
interview helpblock that does not have the
- If you have defined default text for various “screen parts” (such as
submit) using the
metadatablock and you defined values for multiple languages, docassemble will use the value for the current language.
On pages other than interviews, the language that is used for translation purposes is determined as follows:
- If the user is logged in, the user has a “profile” that includes a
language. If the
languagefield in the user’s profile is defined, this language will be used for translations. When a user first registers, this
languagefield is blank. You can use logic in an interview to set it to something. In interviews, you can read this profile by calling
get_user_info()and change it by calling
- If the user is not logged in, or the user does not have a
languagedefined in their profile, docassemble will look for a URL parameter
lang. For example, if you have a web site and you want to put a link on that web site to direct the user to log in to your docassemble server, you could use a URL like
https://docassemble.example.com/user/sign-in?lang=esand the user will see a login screen that is in Spanish. Other URLs with which you might want to use the
- If there is no
langparameter in the URL, docassemble will look for an
Accept-Languageheader in the request from the user’s browser. This is typically set by the user’s web browser to whatever language is defined in the web browser settings. So if the user is a German speaker who is using a web browser that is set up to use the language
de, then the language
dewill be used for translations. In interviews, you can read this language by calling
- If a language cannot be found in the
Accept-Languageheader, the language defined by the
languagedirective in the Configuration is used.
If your interview only works in one language, do not set the
language modifier for any blocks, do not use
and do not call
simply make sure that the default
locale in the
configuration are set to the correct values.
If you have an interview that needs to function in multiple languages,
you will need to have
initial code that calls
docassemble does not remember the active language from one screen
to the next , but the
initial code will make sure that it is
always set to the correct value.
Note that the function
process_action() is called after setting
set_language(). By default, actions are processed at the very
beginning of your interview logic, before your YAML’s
mandatory blocks are processed. However, if you have an
block that needs to define some “ground rules,” such as setting the
operative language, you need to explicitly call
initial block so that the “ground rules” are defined before
actions are processed.
Note that when a user is logged in, they have a user profile, and a
language field is part of their user profile. The value of this
field will determine what language is used when a user logs in and
visits a page like
/interviews. When a user registers, this field
is left unset, and users do not have the ability to change their
language. You can set the
language field in the user profile
during an interview, using code like this:
If you want to avoid asking the user for their language in situations
language field of the user profile has already been
defined, you can use a
code block to set
You can also avoid asking the user for their language by assuming that
they speak whatever language their web browser is set up to use, which
you can determine by calling
docassemble does not handle language selection automatically because there is no one-size-fits-all solution. For example, suppose a user’s primary language was French, but you had some interviews on your system that were only available in English and German. You would want to give the user a chance to select whether they saw the interview in English or German. Handling language selection in the interview logic allows interview developers to customize the way that the applicable language is determined.
The reason for using an
initial block to set the language is based
on the fact that an interview session can have multiple users, who
might speak different languages. For example, you might have a legal
advice interview where the user may be Spanish-speaking but the
advocate may be English-speaking. Here is an interview where the
user object is different depending on whether the active user is the
client or the advocate:
code.yml- for language-independent initial blocks, interview logic, questions, and code blocks.
en.yml- for English-language
default language: enas the first line.
es.yml- for Spanish-language
default language: esas the first line.
interview.yml- the main file, which simply
includes the above three files.
Below is an example of a multi-language interview that asks the user
for a language, then asks for a number, then makes a statement about
the number. The interview is split into the four files listed above,
and all files reside in a folder called
bestnumber within the
The contents of
The contents of
The contents of
Finally, the contents of
While it is generally a good thing that docassemble allows you to
questions that make heavy use of Mako
templating, Markdown, and embedded Python code, a downside is that
all of this “code” can make the translation process more complicated.
Translators may be confused by all of the code, even when you give
them an interview phrase translation file in Excel format. They may
ask you to convert your code to Microsoft Word, putting a great deal
of conversion work on you. Or they may translate what you give them
incorrectly, for example by translating variable names when they
You may be tempted to change the way that you code interviews to
optimize for the needs of the tech-phobic translators you hire. For
example, if you have a single
question that has ten different
variations, you may decide to split this into ten separate
questions so that the translator has an easier time translating.
Or you might decide to remove Mako templating and substitute generic
language that is easier to translate.
However, there is no reason that you should have to make your interview less functional or less maintainable just because the translators you tried to hire were confused by “code.” The solution is to find a different translator. Although hiring a translator other than the “lowest bidder” could increase the out-of-pocket costs of your project, you should think about the net cost of your project, including your own time, and think about costs and benefits in the long term.
While there are many translators who will be confused by having to “translate around code,” there are also many translators for whom “translating around code” is not a problem at all. Companies like Morningside Translations regularly handle technical translations and provide quality control to ensure that the translators do not disturb embedded Python. Shop around before concluding that you have to “dumb down” your interview to make it translatable.
This will use the file
letter_en.docx if the language is English,
letter_es.docx if the language is Spanish, etc. This is
primarily useful if you are using the
translations block for
translating phrases and you are not using the
language modifier on
The documents feature that allows documents to be created from
Markdown text with Mako templating supports languages other than
English to the extent that RTF, Pandoc, and LaTeX do. LaTeX has
support for internationalization, and the default LaTeX template
will load either the polyglossia package or the babel package,
depending on what is available. The language used by LaTeX can be
set using the
mainlang in the
attachment specification. For some languages, you may need to write
your own templates in order to enable fonts that support your
The language-specific functions, many of which are used internally
by docassemble object methods, can all be overridden with your own
versions. You can write special functions that should be used
depending on which language is the active language (as set by
set_language()). For example, there is an internal function
your() that when called as
The default language is English, and there are no definitions for any
other languages, so if you want to use a language other than English,
you will need to write alternatives. For more information about how
to do this, see the sections on language-specific functions and
simple language functions.
While many functions depend on the current language, there are a few
that depend on the locale. One is
nice_number() (one of the
language-specific functions that can be overridden). When the given
number is not among the numbers that should be converted to a word
update_nice_numbers()), it is formatted according to the
locale. For example, in locale
en_US (English, United States),
'6,242,235.4', but in locale
es_ES (Spanish, Spain), it becomes
Other locale-dependent functions are
currency_symbol(). In locale
en_US (English, United States),
'$101.34', but in locale
(Spanish, Spain), it becomes
'101,34 EUR'. In locale
(English, United States),
es_ES (Spanish, Spain), it becomes
The docassemble features that work with currencies are complicated
because the way that currency is represented depends on locale, and
you might want to support more than one locale, but Python’s
module assumes that the locale setting is server-wide.
currency() function and the
are both language-specific functions, which means that you can
substitute your own functions in their place in order to have full
control over currency formatting. For example, if you include the
following in a Python module, then whenever the active language is
French, the currency symbol will be € by default and the
function will return the number followed by €, instead of the currency
symbol followed by the number.
You can also override the default
currency_symbol() functions using the catch-all language
'fr'. You could use
update_locale()) in an
initial block and use
currency_symbol() functions to do different
things depending on the locale.
If you have a specific currency symbol that you want to use on your
server, you can set the
currency symbol directive in the
configuration. This will have a global effect. Suppose you set
this in the configuration:
This is equivalent to doing: