knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
The philosophy of The Carpentries Workbench is one of separation between lesson content and the tooling needed to transform that content into a website. It is possible to write a lesson in any human language that has a syllabary which can be represented on a computer. The only catch is: by default the language of the website template---all the navigational elements of the website---is English, so authors need to tell The Workbench what language the website template should use.
To write a lesson in a specific language, the lesson author should add lang:
'xx'
to the config.yaml
file where xx
represents the language
code
that matches the language of the lesson content. This defaults to "en"
, but
can be any language code (e.g. "ja" specifying Japanese) or combination
language code and country
code
(e.g. "pt_BR" specifies Pourtugese used in Brazil). For more information on how
this is used, see the Locale Names section of the gettext
manual.
If there is country-specific variation for a language that needs to be added,
it is not necessary to re-translate everything that is identical in the original
language file---you only need to translate what is different.
Setting the lang:
keyword will allow the lesson navigational elements of the
website template to be presented in the same language as the lesson content if
the language has been added to {sandpaper}. If not, the menu items will appear
in English.
This vignette is of interest to those who wish to update translations or add new translations. In this vignette I will provide resources for updating and adding new languages, the process by which translation happens, and I will outline special syntax used in {sandpaper}.
To provide translations as a non-maintainer, you need only a text editor to
add translations to the strings present in the .po
translation files (see
more about these files in the Translating in {sandpaper}
section.
If you would like to compile and test these translations locally, you will
need the {potools} package, which
requires the GNU gettext system. As
mentioned in the {potools} installation
documentation, if you
are on macOS, you will likely need to use brew
to install gettext
with brew
install gettext
, otherwise, it is bundled with RTools (needed for package
development on Windows) and it is present on most Linux distributions.
The documentation for the {potools} package is a wonderful resource. Use
vignette("translators", package = "potools")
to read details about what to
consider when translating text in a package. Another really good resource is a
blog post by Maëlle Salmon which
gives a minimum working example of translating package messages using {potools}.
If you are interested in translating lesson content, please consult Joel Nitta's Carpentries translation guide.
You can use tools such as Joel Nitta's {dovetail} for providing a method for translators to track and deploy translations of Carpentries lessons. You can also use rOpenSci's {babeldown}, which uses the DeepL API for automated translation that translators can edit afterwards.
The translations from {sandpaper} are mostly shuffled off to {varnish}, where it has template variables written in mustache templating. These variables define visible menu text such as "Key Points" and screen-reader accessible text for buttons such as "close menu".
There are r length(sandpaper::known_languages())
languages that are known
to {sandpaper}:
writeLines(paste("-", sandpaper::known_languages()))
If a language is not known to {sandpaper} and a lesson attempts to use that language, it will default back to English (the source language).
When you translate in {sandpaper}, you will be working with .po
files, which
are text files that live in the po/
folder in the source of
this package. There is one .po
file per language translated. The syntax looks
like this, where the first line shows the file where the translation exists, the
second line gives the message in English, and the third line gives the
translation:
#: build_404.R:57 msgid "Page not found" msgstr "ページが見つかりません"
These files are recognised by several well-established graphical user interfaces, but since they are text files, you can edit them in any text editor or on GitHub directly.
These po files are compiled into binary .mo
files that are carried with the
built package on to the user's computer. These files are used by the R function
base::gettext()
to translate messages in a specific context. The context for
{sandpaper} is known as R-sandpaper
.
library("withr") library("sandpaper") known_languages() with_language("ja", { enc2utf8(gettext("Page not found", domain = "R-sandpaper")) }) with_language("en", { enc2utf8(gettext("Page not found", domain = "R-sandpaper")) })
If a language does not exist, it will revert to English:
with_language("xx", { enc2utf8(gettext("Page not found", domain = "R-sandpaper")) })
To make translation keys easier to detect, an internal convenience function,
tr_()
has been defined, In addition, the source strings and keys for the
translations can be found from tr_src()
, tr_varnish()
and tr_computed()
,
so if you want to find the context for a given translation key, you can find it
by searching the source code for tr_
.
Some content for translation requires variables or markup to be added after translation.
Items in {curly_braces}
are variables and should remain in English:
#: utils-translate.R:52 msgid "Estimated time: {icons$clock} {minutes} minutes" msgstr "所要時間:{icons$clock} {minutes}分"
Words in <(kirby quotes)>
will have HTML markup surrounding them and should be
translated:
#: utils-translate.R:62 msgid "This lesson is subject to the <(Code of Conduct)>" msgstr "このレッスンは<(行動規範)>の対象となります"
There may be times in the future where translations will need to be updated
because text changes or is added. When this happens, the maintainer of
{sandpaper} will run the following commands to extract the new translation
strings, update all languages, and recompile the .mo
files for the built
package.
potools::po_extract() potools::po_update() potools::po_compile()
When the languages are updated, the translation utility will attempt to make
fuzzy matches or create new strings. For example, if we update the "Page not
found" translation to be title case, add punctuation and a little whimsy to be
"Page? Not Found! -_-;"
, when you go to edit your translation, you
might see something like this:
#: build_404.R:57 #, fuzzy #| msgid "Page not found" msgid "Page? Not Found! -_-;" msgstr "ページが見つかりません"
The old translation will be used until a translator updates it and runs
potools::po_compile()
to update the .mo
files.
When new strings for translations are added, the translation utility does not assume to know anything about translation and the will appear like so:
#: build_404.R:57 msgid "A new translation approaches!" msgstr ""
If no translation is available for a given string, it will default to the string itself:
with_language("ja", { enc2utf8(gettext("A new translation approaches!", domain = "R-sandpaper")) })
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.