diff --git a/NEWS.md b/NEWS.md
index 68f9aa77..45d3ef46 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -13,6 +13,11 @@
* Translations now live in the global environment called `these$translations`
* A new documentation page called `?translate` contains details of how
translations of template elements are rendered.
+- `tr_src()` helper function provides access to the source strings of the
+ translations.
+- `tr_get()`, `tr_varnish()`, and `tr_computed()` helper functions provide
+ access top the lists of translated strings. These have replaced the `tr_()`
+ strings at the point of generation.
# sandpaper 0.16.1 (2023-12-14)
diff --git a/R/build_404.R b/R/build_404.R
index 634e4012..b0a9a6da 100644
--- a/R/build_404.R
+++ b/R/build_404.R
@@ -54,7 +54,7 @@ build_404 <- function(pkg, quiet = FALSE) {
this_dat <- list(
this_page = "404.html",
body = html,
- pagetitle = these$translations$computed$PageNotFound
+ pagetitle = tr_computed("PageNotFound")
)
page_globals$instructor$update(this_dat)
page_globals$learner$update(this_dat)
diff --git a/R/build_aio.R b/R/build_aio.R
index 71295afa..60c9d346 100644
--- a/R/build_aio.R
+++ b/R/build_aio.R
@@ -3,7 +3,7 @@ build_aio <- function(pkg, pages = NULL, quiet = FALSE) {
build_agg_page(
pkg = pkg,
pages = pages,
- title = these$translations$computed$AllInOneView,
+ title = tr_computed("AllInOneView"),
slug = "aio",
aggregate = "*",
prefix = TRUE,
diff --git a/R/build_episode.R b/R/build_episode.R
index 7b0aa1e0..6e722f12 100644
--- a/R/build_episode.R
+++ b/R/build_episode.R
@@ -131,7 +131,7 @@ get_nav_data <- function(path_md, path_src = NULL, home = NULL,
pf_title <- NULL
if (!is.null(page_back)) {
- trhome <- these$translations$varnish$Home
+ trhome <- tr_varnish("Home")
pb_title <- if (page_back == "index.md") trhome else get_trimmed_title(page_back)
page_back <- as_html(page_back)
}
diff --git a/R/build_home.R b/R/build_home.R
index 98b05532..ed1a7c16 100644
--- a/R/build_home.R
+++ b/R/build_home.R
@@ -46,7 +46,7 @@ build_home <- function(pkg, quiet, next_page = NULL) {
needs_title <- nav$pagetitle == ""
if (needs_title) {
- nav$pagetitle <- these$translations$computed$SummaryAndSchedule
+ nav$pagetitle <- tr_computed("SummaryAndSchedule")
}
nav$page_forward <- as_html(nav$page_forward, instructor = TRUE)
page_globals$instructor$update(nav)
@@ -55,7 +55,7 @@ build_home <- function(pkg, quiet, next_page = NULL) {
page_globals$instructor$set("setup", use_instructor(setup))
if (needs_title) {
- nav$pagetitle <- these$translations$computed$SummaryAndSetup
+ nav$pagetitle <- tr_computed("SummaryAndSetup")
}
nav$page_forward <- as_html(nav$page_forward)
page_globals$learner$update(nav)
@@ -98,7 +98,7 @@ format_syllabus <- function(syl, use_col = TRUE) {
}
td1 <- glue::glue(td_template, cls = "col-md-2", thing = syl$timings)
td2 <- glue::glue(td_template, cls = "col-md-3",
- thing = c(links, these$translations$computed$Finish))
+ thing = c(links, tr_computed("Finish")))
td3 <- glue::glue(td_template, cls = "col-md-7", thing = syl$questions)
out <- glue::glue_collapse(glue::glue("
{td1}{td2}{td3}
"), sep = "\n")
tmp <- tempfile(fileext = ".md")
diff --git a/R/build_images.R b/R/build_images.R
index 88bb337b..710194de 100644
--- a/R/build_images.R
+++ b/R/build_images.R
@@ -3,7 +3,7 @@ build_images <- function(pkg, pages = NULL, quiet = FALSE) {
build_agg_page(
pkg = pkg,
pages = pages,
- title = these$translations$computed$AllImages,
+ title = tr_computed("AllImages"),
slug = "images",
aggregate = "/img/..",
prefix = FALSE,
@@ -47,7 +47,7 @@ make_images_section <- function(name, contents, parent) {
alt <- xml2::xml_text(xml2::xml_find_all(content, "./img/@alt"))
n <- length(alt)
xml2::xml_add_child(section, "h3",
- glue::glue(these$translations$computed$Figure),
+ glue::glue(tr_computed("Figure")),
id = glue::glue("{name}-figure-{element}")
)
for (i in seq_along(alt)) {
@@ -58,7 +58,7 @@ make_images_section <- function(name, contents, parent) {
if (txt == "") {
txt <- "[decorative]"
}
- desc <- glue::glue(these$translations$computed$ImageOf)
+ desc <- glue::glue(tr_computed("ImageOf"))
xml2::xml_add_child(section, "p", "aria-hidden" = "true", desc)
}
xml2::xml_add_child(section, contents[[element]])
diff --git a/R/build_instructor_notes.R b/R/build_instructor_notes.R
index 65cfa0d8..c6f84ee2 100644
--- a/R/build_instructor_notes.R
+++ b/R/build_instructor_notes.R
@@ -24,7 +24,7 @@ build_instructor_notes <- function(pkg, pages = NULL, built = NULL, quiet) {
this_dat <- list(
this_page = "instructor-notes.html",
body = use_instructor(html),
- pagetitle = these$translations$varnish$InstructorNotes
+ pagetitle = tr_varnish("InstructorNotes")
)
page_globals$instructor$update(this_dat)
@@ -135,7 +135,7 @@ make_instructor_note_linkback <- function(node, name) {
title <- trimws(xml2::xml_text(node))
id <- xml2::xml_attr(node, "id")
newid <- glue::glue("{name}-{id}")
- tranchor <- these$translations$computed$Anchor
+ tranchor <- tr_computed("Anchor")
anchor <- glue::glue("")
new <- ""
node <- xml2::read_xml(glue::glue(new))
diff --git a/R/build_keypoints.R b/R/build_keypoints.R
index 284199ee..4b49f551 100644
--- a/R/build_keypoints.R
+++ b/R/build_keypoints.R
@@ -3,7 +3,7 @@ build_keypoints <- function(pkg, pages = NULL, quiet = FALSE) {
build_agg_page(
pkg = pkg,
pages = pages,
- title = these$translations$varnish$KeyPoints,
+ title = tr_varnish("KeyPoints"),
slug = "key-points",
aggregate = "/div[starts-with(@id, 'keypoints')]/div[@class='callout-inner']/div[@class='callout-content']/*",
prefix = FALSE,
diff --git a/R/build_profiles.R b/R/build_profiles.R
index 2db43fd2..45a32b58 100644
--- a/R/build_profiles.R
+++ b/R/build_profiles.R
@@ -13,7 +13,7 @@ build_profiles <- function(pkg, quiet) {
this_dat <- list(
this_page = "profiles.html",
body = use_instructor(html),
- pagetitle = these$translations$varnish$LearnerProfiles
+ pagetitle = tr_varnish("LearnerProfiles")
)
page_globals$instructor$update(this_dat)
diff --git a/R/utils-translate.R b/R/utils-translate.R
index 5a11397b..14748be5 100644
--- a/R/utils-translate.R
+++ b/R/utils-translate.R
@@ -1,5 +1,8 @@
-
#' Establish and Manage Translation Strings
+#'
+#' This is documentation for internal functions for translation. If you want a
+#' guide to providing translations, please read `vignette("translations",
+#' package = "sandpaper")`
#'
#' @details A page generated from {sandpaper} is made up of user-provided
#' content wrapped into templated HTML provided by {varnish}. Since users can
@@ -33,15 +36,27 @@
#'
#' @aliases translations
#' @rdname translations
+#' @seealso [known_languages()] for a list of known language codes.
#' @keywords internal
#' @examples
+#' # When sandpaper is loaded, these functions return English
#' snd <- asNamespace("sandpaper")
-#' snd$these$translations$varnish
-#' snd$these$translations$computed
+#' head(snd$tr_varnish())
+#' head(snd$tr_computed())
+#'
+#' # Setting language to Spanish will translate the computed and varnish
#' snd$set_language("es")
-#' snd$these$translations$computed
-#' snd$set_language() # defaults to English
-#' snd$these$translations$computed
+#' head(snd$tr_varnish())
+#' head(snd$tr_computed())
+#'
+#' # The source will remain the same
+#' head(snd$tr_src("varnish"))
+#' head(snd$tr_src("computed"))
+#'
+#' # Running set_language with no arguments defaults to English
+#' snd$set_language()
+#' head(snd$tr_varnish())
+#' head(snd$tr_computed())
these <- new.env(parent = emptyenv())
#' @rdname translations
@@ -165,6 +180,13 @@ establish_translation_vars <- function() {
src = list(varnish = varnish, computed = computed),
varnish = varnish,
computed = computed
+ # NOTE: If you want to include translations for messages to the user in
+ # their own language, they could be added to this list and then the
+ # message functions (e.g. those in R/utils-cli.R) could use
+ # a key from these$translations$msg
+ # msg = list(
+ # RemovedFile = tr_("Removed {what}"),
+ # )
)
}
@@ -195,6 +217,7 @@ add_varnish_translations <- function() {
these$translations$varnish <- lapply(to_translate$varnish, tr_)
these$translations$computed <- lapply(to_translate$computed, tr_)
}
+
#' Show a list of languages known by {sandpaper}
#'
#' @return a character vector of language codes known by {sandpaper}
@@ -212,6 +235,8 @@ add_varnish_translations <- function() {
#' writeLines(paste("-", langs))
#' ```
#'
+#' @seealso `vignette("translations", package = "sandpaper")` for an overview
+#' of providing translations.
#' @export
#' @examples
#' known_languages()
@@ -229,6 +254,44 @@ is_known_language <- function(lang = NULL, warn = FALSE) {
return(!not_known)
}
+#' @param from a single character specifying the translation list to fetch.
+#' This defaults to "varnish" but can be one of the following:
+#' ```{r echo = FALSE, results = "asis"}
+#' writeLines(paste("-", names(these$translations)))
+#' ```
+#' @param key a single character specifying a specific key to fetch from the
+#' translation list. This defaults to `NULL`, returning the whole list.
+#' @return if `key = NULL`, a list if `key` is a single character, the result
+#' will be an unnamed character vector of length 1 representing the value from
+#' that list.
+#' @rdname translations
+tr_src <- function(from = "varnish", key = NULL) {
+ res <- these$translations$src[[from]]
+ if (length(key) == 1L) {
+ res <- res[[key]]
+ }
+ return(res)
+}
+
+#' @rdname translations
+tr_get <- function(from = "varnish", key = NULL) {
+ res <- these$translations[[from]]
+ if (length(key) == 1L) {
+ res <- res[[key]]
+ }
+ return(res)
+}
+
+#' @rdname translations
+tr_varnish <- function(key = NULL) {
+ tr_get(from = "varnish", key = key)
+}
+
+#' @rdname translations
+tr_computed <- function(key = NULL) {
+ tr_get(from = "computed", key = key)
+}
+
# Apply translations to text assuming that the names of the translations
# matches the text
@@ -254,7 +317,7 @@ get_codeblock_translations <- function() {
needed <- c("OUTPUT",
"ERROR",
"WARNING")
- unlist(these$translations$computed[needed])
+ unlist(tr_computed()[needed])
}
# generator for translations of callout blocks and accordions
@@ -266,7 +329,7 @@ get_callout_translations <- function() {
"Discussion",
"Testimonial",
"Keypoints")
- unlist(these$translations$computed[needed])
+ unlist(tr_computed()[needed])
}
get_accordion_translations <- function() {
@@ -275,7 +338,7 @@ get_accordion_translations <- function() {
"Show details",
"Instructor Note"
)
- unlist(these$translations$computed[needed])
+ unlist(tr_computed()[needed])
}
# replace text string with a <(kirby template)> with link text
diff --git a/R/utils-varnish.R b/R/utils-varnish.R
index c1f28d85..e699261d 100644
--- a/R/utils-varnish.R
+++ b/R/utils-varnish.R
@@ -86,7 +86,7 @@ set_globals <- function(path) {
idx_text <- xml2::xml_contents(idx_link)
no_index_title <- length(idx_text) == 1 && xml2::xml_text(idx_text) == "0. "
if (no_index_title) {
- xml2::xml_set_text(idx_link, these$translations$computed$SummaryAndSchedule)
+ xml2::xml_set_text(idx_link, tr_computed("SummaryAndSchedule"))
} else {
xml2::xml_set_text(idx_text, sub("^0[.] ", "", xml2::xml_text(idx_text)))
}
@@ -94,7 +94,7 @@ set_globals <- function(path) {
learner_sidebar <- instructor_sidebar
instructor_sidebar[[1]] <- sindex
if (no_index_title) {
- xml2::xml_set_text(idx_link, these$translations$computed$SummaryAndSetup)
+ xml2::xml_set_text(idx_link, tr_computed("SummaryAndSetup"))
sindex <- create_sidebar_item(nodes = NULL, as.character(idx_link), 1)
}
learner_sidebar[[1]] <- sindex
@@ -115,7 +115,7 @@ set_globals <- function(path) {
sidebar = learner_sidebar,
more = paste(learner$extras, collapse = ""),
resources = paste(learner$resources, collapse = ""),
- translate = these$translations$varnish
+ translate = tr_varnish()
), pkg_versions)
)
instructor_globals$set(key = NULL,
@@ -125,7 +125,7 @@ set_globals <- function(path) {
sidebar = instructor_sidebar,
more = paste(instructor$extras, collapse = ""),
resources = paste(instructor$resources, collapse = ""),
- translate = these$translations$varnish
+ translate = tr_varnish()
), pkg_versions)
)
}
diff --git a/R/utils-xml.R b/R/utils-xml.R
index 22687cb2..3ba9a126 100644
--- a/R/utils-xml.R
+++ b/R/utils-xml.R
@@ -130,7 +130,7 @@ add_class <- function(nodes, new) {
}
add_anchors <- function(nodes, ids) {
- tranchor <- these$translations$computed$Anchor
+ tranchor <- tr_computed("Anchor")
anchor <- paste0(
""
)
@@ -158,7 +158,7 @@ translate_overview <- function(nodes = NULL) {
opath <- ".//div[starts-with(@class, 'inner')]/h3[@class='card-title'][text()='Objectives']"
questions <- xml2::xml_find_first(card, qpath)
objectives <- xml2::xml_find_first(card, opath)
- translated <- these$translations$computed
+ translated <- tr_computed()
xml2::xml_set_text(questions, translated[["Questions"]])
xml2::xml_set_text(objectives, translated[["Objectives"]])
diff --git a/man/children/translation-vars.Rmd b/man/children/translation-vars.Rmd
index 9d4f518c..837479cb 100644
--- a/man/children/translation-vars.Rmd
+++ b/man/children/translation-vars.Rmd
@@ -1,20 +1,20 @@
-There are `r length(asNamespace("sandpaper")$these$translations$src$varnish)` translations generated by
+There are `r length(asNamespace("sandpaper")$tr_src("varnish"))` translations generated by
`set_language()` that correspond to the following variables in {varnish}:
```{r translation-list, results = "asis", echo = FALSE}
snd <- asNamespace("sandpaper")
res <- glue::glue("| `translate.{names(tr)}` | `{sQuote(tr, q = 2)}` |",
- tr = snd$these$translations$src$varnish)
+ tr = snd$tr_src("varnish"))
writeLines(c("| variable | string |\n| --- | --- |", res))
```
-In addition, there are `r length(asNamespace("sandpaper")$these$translations$src$computed)` translations
+In addition, there are `r length(asNamespace("sandpaper")$tr_src("computed"))` translations
that are inserted _before_ they get to {varnish}:
```{r translation-list-computed, results = "asis", echo = FALSE}
snd <- asNamespace("sandpaper")
res <- glue::glue("| `{names(tr)}` | `{sQuote(tr, q = 2)}` |",
- tr = snd$these$translations$src$computed)
+ tr = snd$tr_src("computed"))
writeLines(c("| variable | string |\n| --- | --- |", res))
```
diff --git a/man/known_languages.Rd b/man/known_languages.Rd
index 5cbc1feb..add14421 100644
--- a/man/known_languages.Rd
+++ b/man/known_languages.Rd
@@ -29,3 +29,7 @@ details of how to do so in the source code for {sandpaper}.
\examples{
known_languages()
}
+\seealso{
+\code{vignette("translations", package = "sandpaper")} for an overview
+of providing translations.
+}
diff --git a/man/translations.Rd b/man/translations.Rd
index 5dcdefca..7c787ac9 100644
--- a/man/translations.Rd
+++ b/man/translations.Rd
@@ -6,6 +6,10 @@
\alias{translations}
\alias{establish_translation_vars}
\alias{set_language}
+\alias{tr_src}
+\alias{tr_get}
+\alias{tr_varnish}
+\alias{tr_computed}
\title{Establish and Manage Translation Strings}
\format{
An object of class \code{environment} of length 1.
@@ -16,14 +20,39 @@ these
establish_translation_vars()
set_language(lang = NULL)
+
+tr_src(from = "varnish", key = NULL)
+
+tr_get(from = "varnish", key = NULL)
+
+tr_varnish(key = NULL)
+
+tr_computed(key = NULL)
}
\arguments{
\item{lang}{a two-letter language code (optionally with a country code).
Defaults to \code{NULL}, which falls back to English (the language of the
source code).}
+
+\item{from}{a single character specifying the translation list to fetch.
+This defaults to "varnish" but can be one of the following:
+\itemize{
+\item src
+\item varnish
+\item computed
+}}
+
+\item{key}{a single character specifying a specific key to fetch from the
+translation list. This defaults to \code{NULL}, returning the whole list.}
+}
+\value{
+if \code{key = NULL}, a list if \code{key} is a single character, the result
+will be an unnamed character vector of length 1 representing the value from
+that list.
}
\description{
-Establish and Manage Translation Strings
+This is documentation for internal functions for translation. If you want a
+guide to providing translations, please read \code{vignette("translations", package = "sandpaper")}
}
\details{
A page generated from {sandpaper} is made up of user-provided
@@ -155,12 +184,26 @@ that are inserted \emph{before} they get to {varnish}:\tabular{ll}{
}
}
\examples{
+# When sandpaper is loaded, these functions return English
snd <- asNamespace("sandpaper")
-snd$these$translations$varnish
-snd$these$translations$computed
+head(snd$tr_varnish())
+head(snd$tr_computed())
+
+# Setting language to Spanish will translate the computed and varnish
snd$set_language("es")
-snd$these$translations$computed
-snd$set_language() # defaults to English
-snd$these$translations$computed
+head(snd$tr_varnish())
+head(snd$tr_computed())
+
+# The source will remain the same
+head(snd$tr_src("varnish"))
+head(snd$tr_src("computed"))
+
+# Running set_language with no arguments defaults to English
+snd$set_language()
+head(snd$tr_varnish())
+head(snd$tr_computed())
+}
+\seealso{
+\code{\link[=known_languages]{known_languages()}} for a list of known language codes.
}
\keyword{internal}
diff --git a/po/R-es.po b/po/R-es.po
index ec58e446..335f8bd2 100644
--- a/po/R-es.po
+++ b/po/R-es.po
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: sandpaper 0.15.0.9000\n"
-"POT-Creation-Date: 2023-12-18 09:27-0800\n"
+"POT-Creation-Date: 2023-12-19 09:37-0800\n"
"PO-Revision-Date: 2023-12-06 11:03-0800\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
@@ -11,15 +11,15 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: utils-translate.R:12
+#: utils-translate.R:74
msgid "Skip to main content"
msgstr "Ir al contenido principal"
-#: utils-translate.R:13
+#: utils-translate.R:75
msgid "Pre-Alpha"
msgstr "Pre-Alfa"
-#: utils-translate.R:14
+#: utils-translate.R:76
msgid ""
"This lesson is in the pre-alpha phase, which means that it is in early "
"development, but has not yet been taught."
@@ -27,7 +27,7 @@ msgstr ""
"Esta lección se encuentra en la fase pre-alfa, lo que significa que está en "
"las primeras etapas de desarrollo, pero aún no se ha enseñado."
-#: utils-translate.R:15
+#: utils-translate.R:77
msgid ""
"This lesson is in the alpha phase, which means that it has been taught once "
"and lesson authors are iterating on feedback."
@@ -36,11 +36,11 @@ msgstr ""
"enseñado una vesy las autoras de la lección están trabajando en los "
"comentarios."
-#: utils-translate.R:16
+#: utils-translate.R:78
msgid "Alpha"
msgstr "Alfa"
-#: utils-translate.R:17
+#: utils-translate.R:79
msgid ""
"This lesson is in the beta phase, which means that it is ready for teaching "
"by instructors outside of the original author team."
@@ -48,147 +48,147 @@ msgstr ""
"Esta lección se encuentra en la fase beta, lo que significa que está lista "
"para enseñarpor instructoras que no son parte del equipo original de autoras"
-#: utils-translate.R:18
+#: utils-translate.R:80
msgid "Beta"
msgstr "Beta"
-#: utils-translate.R:19
+#: utils-translate.R:81
msgid "This lesson has passed peer review."
msgstr "Esta lección pasó la revisión por pares."
-#: utils-translate.R:20
+#: utils-translate.R:82
msgid "Instructor View"
msgstr "Vista de la instructora"
-#: utils-translate.R:21
+#: utils-translate.R:83
msgid "Learner View"
msgstr "Vista de estudiante"
-#: utils-translate.R:22
+#: utils-translate.R:84
msgid "Main Navigation"
msgstr "Navegación principal"
-#: utils-translate.R:23
+#: utils-translate.R:85
msgid "Toggle Navigation"
msgstr "Alternar navegación"
-#: utils-translate.R:24
+#: utils-translate.R:86
msgid "Menu"
msgstr "Menú"
-#: utils-translate.R:25
+#: utils-translate.R:87
msgid "search button"
msgstr "botón de buscar"
-#: utils-translate.R:26
+#: utils-translate.R:88
msgid "Setup"
msgstr "Configuración"
-#: utils-translate.R:27
+#: utils-translate.R:89
msgid "Key Points"
msgstr "Puntos Clave"
-#: utils-translate.R:28
+#: utils-translate.R:90
msgid "Instructor Notes"
msgstr "Notas de la instructora"
-#: utils-translate.R:29
+#: utils-translate.R:91
msgid "Glossary"
msgstr "Glosario"
-#: utils-translate.R:30
+#: utils-translate.R:92
msgid "Learner Profiles"
msgstr "Perfiles de estudiante"
-#: utils-translate.R:31
+#: utils-translate.R:93
msgid "More"
msgstr "Más"
-#: utils-translate.R:32
+#: utils-translate.R:94
msgid "Search"
msgstr "Buscar"
-#: utils-translate.R:33
+#: utils-translate.R:95
msgid "Lesson Progress"
msgstr "Progreso de la lección"
-#: utils-translate.R:35
+#: utils-translate.R:97
msgid "close menu"
msgstr "Cerrar menú"
-#: utils-translate.R:36
+#: utils-translate.R:98
msgid "EPISODES"
msgstr "EPISODIOS"
-#: utils-translate.R:37
+#: utils-translate.R:99
msgid "Home"
msgstr "Inicio"
-#: utils-translate.R:38
+#: utils-translate.R:100
msgid "Home Page Navigation"
msgstr "Navegación de la página de inicio"
-#: utils-translate.R:39
+#: utils-translate.R:101
msgid "RESOURCES"
msgstr "RECURSOS"
-#: utils-translate.R:40
+#: utils-translate.R:102
msgid "Extract All Images"
msgstr "Extraer todas las imágenes"
-#: utils-translate.R:41
+#: utils-translate.R:103
msgid "See all in one page"
msgstr "Todo en una sola página"
-#: utils-translate.R:42
+#: utils-translate.R:104
msgid "Download Lesson Handout"
msgstr "Descargar el material de la lección"
-#: utils-translate.R:43
+#: utils-translate.R:105
msgid "Export Chapter Slides"
msgstr "Exportar las diapositivas del capítulo"
-#: utils-translate.R:45
+#: utils-translate.R:107
msgid "Previous and Next Chapter"
msgstr "Capítulo previo y siguiente"
-#: utils-translate.R:46
+#: utils-translate.R:108
msgid "Previous"
msgstr "Previo"
-#: utils-translate.R:47
+#: utils-translate.R:109
msgid "Estimated time: {icons$clock} {minutes} minutes"
msgstr "Tiempo estimado: {icons$clock} {minutes} minutos"
-#: utils-translate.R:48
+#: utils-translate.R:110
msgid "Next"
msgstr "Siguiente"
-#: utils-translate.R:49
+#: utils-translate.R:111
msgid "Next Chapter"
msgstr "Capítulo Siguiente"
-#: utils-translate.R:50
+#: utils-translate.R:112
msgid "Last updated on {updated}"
msgstr "Última actualización: {updated}"
-#: utils-translate.R:51
+#: utils-translate.R:113
msgid "Edit this page"
msgstr "Mejora esta página"
-#: utils-translate.R:52 utils-translate.R:73
+#: utils-translate.R:114 utils-translate.R:135
msgid "Expand All Solutions"
msgstr "Mostrar todas las soluciones"
-#: utils-translate.R:54
+#: utils-translate.R:116
msgid "Setup Instructions"
msgstr "Configuración"
-#: utils-translate.R:55
+#: utils-translate.R:117
msgid "Download files required for the lesson"
msgstr "Descargar los archivos necesarios para la lección"
-#: utils-translate.R:56
+#: utils-translate.R:118
msgid ""
"The actual schedule may vary slightly depending on the topics and exercises "
"chosen by the instructor."
@@ -196,178 +196,178 @@ msgstr ""
"El horario real puede variar ligeramente dependiendo de los temas y "
"ejercicios elegidos por la instructora."
-#: utils-translate.R:58
+#: utils-translate.R:120
msgid "Back To Top"
msgstr "Volver al inicio"
-#: utils-translate.R:59
+#: utils-translate.R:121
msgid "<(Back)> To Top"
msgstr "<(Volver)> al inicio"
-#: utils-translate.R:60
+#: utils-translate.R:122
msgid "This lesson is subject to the <(Code of Conduct)>"
msgstr "Esta lección está sujeta al <(Código de Conducta)>"
-#: utils-translate.R:61
+#: utils-translate.R:123
msgid "Code of Conduct"
msgstr "Código de Conducta"
-#: utils-translate.R:62
+#: utils-translate.R:124
msgid "Edit on GitHub"
msgstr "Editar en GitHub"
-#: utils-translate.R:63
+#: utils-translate.R:125
msgid "Contributing"
msgstr "Contribuir"
-#: utils-translate.R:64
+#: utils-translate.R:126
msgid "Source"
msgstr "Fuente"
-#: utils-translate.R:65
+#: utils-translate.R:127
msgid "Cite"
msgstr "Cita"
-#: utils-translate.R:66
+#: utils-translate.R:128
msgid "Contact"
msgstr "Contacto"
-#: utils-translate.R:67
+#: utils-translate.R:129
msgid "About"
msgstr "Acerca de"
-#: utils-translate.R:68
+#: utils-translate.R:130
msgid "Materials licensed under {license} by {authors}"
msgstr "Materiales bajo la {license} por {authors}"
-#: utils-translate.R:69
+#: utils-translate.R:131
msgid "Template licensed under <(CC-BY 4.0)> by {template_authors}"
msgstr "Plantilla compartida bajo <(CC-BY 4.0)> por {template_authors}"
-#: utils-translate.R:70
+#: utils-translate.R:132
msgid "The Carpentries"
msgstr "The Carpentries"
-#: utils-translate.R:71
+#: utils-translate.R:133
msgid "Built with {sandpaper_link}, {pegboard_link}, and {varnish_link}"
msgstr "Construido con {sandpaper_link}, {pegboard_link} y {varnish_link}"
-#: utils-translate.R:74
+#: utils-translate.R:136
msgid "Collapse All Solutions"
msgstr "Cerrar todas las soluciones"
-#: utils-translate.R:75
+#: utils-translate.R:137
msgid "Collapse"
msgstr "Cerrar"
-#: utils-translate.R:76
+#: utils-translate.R:138
msgid "Episodes"
msgstr "Episodios"
-#: utils-translate.R:78
+#: utils-translate.R:140
msgid "Give Feedback"
msgstr "Dar feedback"
-#: utils-translate.R:79
+#: utils-translate.R:141
msgid "Learn More"
msgstr "Aprender más"
-#: utils-translate.R:85
+#: utils-translate.R:147
msgid "OUTPUT"
msgstr "SALIDA"
-#: utils-translate.R:86
+#: utils-translate.R:148
msgid "WARNING"
msgstr "ADVERTENCIA"
-#: utils-translate.R:87
+#: utils-translate.R:149
msgid "ERROR"
msgstr "ERROR"
-#: utils-translate.R:89
+#: utils-translate.R:151
msgid "Overview"
msgstr "Hoja de ruta"
-#: utils-translate.R:90
+#: utils-translate.R:152
msgid "Questions"
msgstr "Preguntas"
-#: utils-translate.R:91
+#: utils-translate.R:153
msgid "Objectives"
msgstr "Objetivos"
-#: utils-translate.R:92
+#: utils-translate.R:154
msgid "Callout"
msgstr "Aviso"
-#: utils-translate.R:93
+#: utils-translate.R:155
msgid "Challenge"
msgstr "Desafío"
-#: utils-translate.R:94
+#: utils-translate.R:156
msgid "Prerequisite"
msgstr "Pre requisito"
-#: utils-translate.R:95
+#: utils-translate.R:157
msgid "Checklist"
msgstr "Lista de verificación"
-#: utils-translate.R:96
+#: utils-translate.R:158
msgid "Discussion"
msgstr "Discusión"
-#: utils-translate.R:97
+#: utils-translate.R:159
msgid "Testimonial"
msgstr "Testimonio"
-#: utils-translate.R:100
+#: utils-translate.R:162
msgid "Show me the solution"
msgstr "Mostrar la solución"
-#: utils-translate.R:101
+#: utils-translate.R:163
msgid "Give me a hint"
msgstr "Dar una pista"
-#: utils-translate.R:102
+#: utils-translate.R:164
msgid "Show details"
msgstr "Mostrar detalles"
-#: utils-translate.R:103
+#: utils-translate.R:165
msgid "Instructor Note"
msgstr "Notas de la instructora"
-#: utils-translate.R:105
+#: utils-translate.R:167
msgid "Summary and Setup"
msgstr "Resumen y configuración"
-#: utils-translate.R:106
+#: utils-translate.R:168
msgid "Summary and Schedule"
msgstr "Resumen y agenda"
-#: utils-translate.R:107
+#: utils-translate.R:169
msgid "All in One View"
msgstr "Todo en una sola página"
-#: utils-translate.R:108
+#: utils-translate.R:170
msgid "Page not found"
msgstr "Página no encontrada"
-#: utils-translate.R:109
+#: utils-translate.R:171
msgid "All Images"
msgstr "Todas las imágenes"
-#: utils-translate.R:111
+#: utils-translate.R:173
msgid "anchor"
msgstr "anclaje"
-#: utils-translate.R:112
+#: utils-translate.R:174
msgid "Figure {element}"
msgstr "Figura {element}"
-#: utils-translate.R:113
+#: utils-translate.R:175
msgid "Image {i} of {n}: {sQuote(txt)}"
msgstr "Imagen {i} de {n}: {sQuote(txt)}"
-#: utils-translate.R:114
+#: utils-translate.R:176
msgid "Finish"
msgstr "Final"
diff --git a/po/R-ja.po b/po/R-ja.po
index 2c2efb3d..cb49816c 100644
--- a/po/R-ja.po
+++ b/po/R-ja.po
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: sandpaper 0.14.1.9000\n"
-"POT-Creation-Date: 2023-12-18 09:27-0800\n"
+"POT-Creation-Date: 2023-12-19 09:37-0800\n"
"PO-Revision-Date: 2023-11-22 09:14+0900\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
@@ -11,15 +11,15 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-#: utils-translate.R:12
+#: utils-translate.R:74
msgid "Skip to main content"
msgstr "本文へ移動"
-#: utils-translate.R:13
+#: utils-translate.R:75
msgid "Pre-Alpha"
msgstr "プレアルファ"
-#: utils-translate.R:14
+#: utils-translate.R:76
msgid ""
"This lesson is in the pre-alpha phase, which means that it is in early "
"development, but has not yet been taught."
@@ -27,7 +27,7 @@ msgstr ""
"このレッスンはプレアルファフェーズ(開発が始まったが、まだ教えられたことがな"
"い)にある。"
-#: utils-translate.R:15
+#: utils-translate.R:77
msgid ""
"This lesson is in the alpha phase, which means that it has been taught once "
"and lesson authors are iterating on feedback."
@@ -35,11 +35,11 @@ msgstr ""
"このレッスンはアルファフェーズ(一度教えられ、レッスン作成者がフィードバック"
"を反復している)にある。"
-#: utils-translate.R:16
+#: utils-translate.R:78
msgid "Alpha"
msgstr "アルファ"
-#: utils-translate.R:17
+#: utils-translate.R:79
msgid ""
"This lesson is in the beta phase, which means that it is ready for teaching "
"by instructors outside of the original author team."
@@ -47,147 +47,147 @@ msgstr ""
"このレッスンはベタフェーズ(原著者チーム以外の指導者にも教える準備が整ってい"
"る)にある"
-#: utils-translate.R:18
+#: utils-translate.R:80
msgid "Beta"
msgstr "ベタ"
-#: utils-translate.R:19
+#: utils-translate.R:81
msgid "This lesson has passed peer review."
msgstr "このレッスンはピアレビューに合格しました"
-#: utils-translate.R:20
+#: utils-translate.R:82
msgid "Instructor View"
msgstr "インストラクター表示"
-#: utils-translate.R:21
+#: utils-translate.R:83
msgid "Learner View"
msgstr "学習者表示"
-#: utils-translate.R:22
+#: utils-translate.R:84
msgid "Main Navigation"
msgstr "メインナビゲーション"
-#: utils-translate.R:23
+#: utils-translate.R:85
msgid "Toggle Navigation"
msgstr "ナビゲーションの切り替え"
-#: utils-translate.R:24
+#: utils-translate.R:86
msgid "Menu"
msgstr "メニュー"
-#: utils-translate.R:25
+#: utils-translate.R:87
msgid "search button"
msgstr "検索ボタン"
-#: utils-translate.R:26
+#: utils-translate.R:88
msgid "Setup"
msgstr "セットアップ"
-#: utils-translate.R:27
+#: utils-translate.R:89
msgid "Key Points"
msgstr "まとめ"
-#: utils-translate.R:28
+#: utils-translate.R:90
msgid "Instructor Notes"
msgstr "インストラクター用メモ"
-#: utils-translate.R:29
+#: utils-translate.R:91
msgid "Glossary"
msgstr "用語集"
-#: utils-translate.R:30
+#: utils-translate.R:92
msgid "Learner Profiles"
msgstr "学習者プロフィール"
-#: utils-translate.R:31
+#: utils-translate.R:93
msgid "More"
msgstr "その他"
-#: utils-translate.R:32
+#: utils-translate.R:94
msgid "Search"
msgstr "検索"
-#: utils-translate.R:33
+#: utils-translate.R:95
msgid "Lesson Progress"
msgstr "レッスンの進捗状況"
-#: utils-translate.R:35
+#: utils-translate.R:97
msgid "close menu"
msgstr "メニューを閉じる"
-#: utils-translate.R:36
+#: utils-translate.R:98
msgid "EPISODES"
msgstr "エピソード"
-#: utils-translate.R:37
+#: utils-translate.R:99
msgid "Home"
msgstr "ホーム"
-#: utils-translate.R:38
+#: utils-translate.R:100
msgid "Home Page Navigation"
msgstr "ホームページのナビゲーション"
-#: utils-translate.R:39
+#: utils-translate.R:101
msgid "RESOURCES"
msgstr "資料"
-#: utils-translate.R:40
+#: utils-translate.R:102
msgid "Extract All Images"
msgstr "全ての画像"
-#: utils-translate.R:41
+#: utils-translate.R:103
msgid "See all in one page"
msgstr "一つにまとまったページ"
-#: utils-translate.R:42
+#: utils-translate.R:104
msgid "Download Lesson Handout"
msgstr "レッスンのプリントをダウンロード"
-#: utils-translate.R:43
+#: utils-translate.R:105
msgid "Export Chapter Slides"
msgstr "スライドのエキスポート"
-#: utils-translate.R:45
+#: utils-translate.R:107
msgid "Previous and Next Chapter"
msgstr "前の章と次の章"
-#: utils-translate.R:46
+#: utils-translate.R:108
msgid "Previous"
msgstr "前へ"
-#: utils-translate.R:47
+#: utils-translate.R:109
msgid "Estimated time: {icons$clock} {minutes} minutes"
msgstr "所要時間:{icons$clock} {minutes}分"
-#: utils-translate.R:48
+#: utils-translate.R:110
msgid "Next"
msgstr "次へ"
-#: utils-translate.R:49
+#: utils-translate.R:111
msgid "Next Chapter"
msgstr "次のチャプター"
-#: utils-translate.R:50
+#: utils-translate.R:112
msgid "Last updated on {updated}"
msgstr "最終更新日:{updated}"
-#: utils-translate.R:51
+#: utils-translate.R:113
msgid "Edit this page"
msgstr "ページの編集"
-#: utils-translate.R:52 utils-translate.R:73
+#: utils-translate.R:114 utils-translate.R:135
msgid "Expand All Solutions"
msgstr "回答を全て表示する"
-#: utils-translate.R:54
+#: utils-translate.R:116
msgid "Setup Instructions"
msgstr "セットアップの手順"
-#: utils-translate.R:55
+#: utils-translate.R:117
msgid "Download files required for the lesson"
msgstr "レッスンに必要なファイルのダウンロード"
-#: utils-translate.R:56
+#: utils-translate.R:118
msgid ""
"The actual schedule may vary slightly depending on the topics and exercises "
"chosen by the instructor."
@@ -195,182 +195,182 @@ msgstr ""
"実際のスケジュールは、講師が選んだトピックやエクササイズによって多少異なる場"
"合があります。"
-#: utils-translate.R:58
+#: utils-translate.R:120
msgid "Back To Top"
msgstr "上へ戻る"
-#: utils-translate.R:59
+#: utils-translate.R:121
msgid "<(Back)> To Top"
msgstr "上へ<(戻る)>"
-#: utils-translate.R:60
+#: utils-translate.R:122
msgid "This lesson is subject to the <(Code of Conduct)>"
msgstr "このレッスンは<(行動規範)>の対象となっている"
-#: utils-translate.R:61
+#: utils-translate.R:123
msgid "Code of Conduct"
msgstr "行動規範"
-#: utils-translate.R:62
+#: utils-translate.R:124
msgid "Edit on GitHub"
msgstr "GitHubで編集"
-#: utils-translate.R:63
+#: utils-translate.R:125
msgid "Contributing"
msgstr "貢献"
-#: utils-translate.R:64
+#: utils-translate.R:126
msgid "Source"
msgstr "ソース"
-#: utils-translate.R:65
+#: utils-translate.R:127
msgid "Cite"
msgstr "引用"
-#: utils-translate.R:66
+#: utils-translate.R:128
msgid "Contact"
msgstr "お問い合わせ"
-#: utils-translate.R:67
+#: utils-translate.R:129
msgid "About"
msgstr "概要"
-#: utils-translate.R:68
+#: utils-translate.R:130
msgid "Materials licensed under {license} by {authors}"
msgstr "材料は{authors}によって{license}のもとに掲載を許諾されている"
-#: utils-translate.R:69
+#: utils-translate.R:131
msgid "Template licensed under <(CC-BY 4.0)> by {template_authors}"
msgstr ""
"テンプレートは{template_authors}によって<(CC-BY 4.0)>のもとに掲載を許諾されて"
"いる"
-#: utils-translate.R:70
+#: utils-translate.R:132
msgid "The Carpentries"
msgstr "ザ・カーペントリーズ"
-#: utils-translate.R:71
+#: utils-translate.R:133
msgid "Built with {sandpaper_link}, {pegboard_link}, and {varnish_link}"
msgstr ""
"このレッスンは{sandpaper_link}、{pegboard_link}、および{varnish_link}によって"
"作られた"
-#: utils-translate.R:74
+#: utils-translate.R:136
msgid "Collapse All Solutions"
msgstr "回答を全て折りたたむ"
-#: utils-translate.R:75
+#: utils-translate.R:137
msgid "Collapse"
msgstr "折りたたむ"
-#: utils-translate.R:76
+#: utils-translate.R:138
msgid "Episodes"
msgstr "エピソード"
-#: utils-translate.R:78
+#: utils-translate.R:140
msgid "Give Feedback"
msgstr "フィードバック"
-#: utils-translate.R:79
+#: utils-translate.R:141
msgid "Learn More"
msgstr "さらに詳しく"
-#: utils-translate.R:85
+#: utils-translate.R:147
msgid "OUTPUT"
msgstr "出力"
-#: utils-translate.R:86
+#: utils-translate.R:148
msgid "WARNING"
msgstr "警告"
-#: utils-translate.R:87
+#: utils-translate.R:149
msgid "ERROR"
msgstr "エラー"
-#: utils-translate.R:89
+#: utils-translate.R:151
msgid "Overview"
msgstr "概要"
-#: utils-translate.R:90
+#: utils-translate.R:152
msgid "Questions"
msgstr "質問"
-#: utils-translate.R:91
+#: utils-translate.R:153
msgid "Objectives"
msgstr "目的"
-#: utils-translate.R:92
+#: utils-translate.R:154
msgid "Callout"
msgstr "コールアウト"
-#: utils-translate.R:93
+#: utils-translate.R:155
msgid "Challenge"
msgstr "チャレンジ"
-#: utils-translate.R:94
+#: utils-translate.R:156
msgid "Prerequisite"
msgstr "必須条件"
-#: utils-translate.R:95
+#: utils-translate.R:157
msgid "Checklist"
msgstr "チェックリスト"
-#: utils-translate.R:96
+#: utils-translate.R:158
msgid "Discussion"
msgstr "ディスカッション"
-#: utils-translate.R:97
+#: utils-translate.R:159
msgid "Testimonial"
msgstr "推薦文"
-#: utils-translate.R:100
+#: utils-translate.R:162
msgid "Show me the solution"
msgstr "回答を表示する"
-#: utils-translate.R:101
+#: utils-translate.R:163
msgid "Give me a hint"
msgstr "ヒントを表示する"
-#: utils-translate.R:102
+#: utils-translate.R:164
msgid "Show details"
msgstr "詳細を表示する"
-#: utils-translate.R:103
+#: utils-translate.R:165
msgid "Instructor Note"
msgstr "インストラクター用メモ"
-#: utils-translate.R:105
+#: utils-translate.R:167
msgid "Summary and Setup"
msgstr "概要とセットアップ"
-#: utils-translate.R:106
+#: utils-translate.R:168
msgid "Summary and Schedule"
msgstr "概要とスケジュール"
-#: utils-translate.R:107
+#: utils-translate.R:169
msgid "All in One View"
msgstr "一つにまとまったページ"
-#: utils-translate.R:108
+#: utils-translate.R:170
msgid "Page not found"
msgstr "ページが見つかりません"
-#: utils-translate.R:109
+#: utils-translate.R:171
msgid "All Images"
msgstr "全ての画像"
-#: utils-translate.R:111
+#: utils-translate.R:173
msgid "anchor"
msgstr "アンカー"
-#: utils-translate.R:112
+#: utils-translate.R:174
msgid "Figure {element}"
msgstr "図の{element}"
-#: utils-translate.R:113
+#: utils-translate.R:175
msgid "Image {i} of {n}: {sQuote(txt)}"
msgstr "画像{i}/{n}: {sQuote(txt)}"
-#: utils-translate.R:114
+#: utils-translate.R:176
msgid "Finish"
msgstr "終わり"
diff --git a/po/R-sandpaper.pot b/po/R-sandpaper.pot
index 290da473..8f2a2d77 100644
--- a/po/R-sandpaper.pot
+++ b/po/R-sandpaper.pot
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
-"Project-Id-Version: sandpaper 0.16.1\n"
-"POT-Creation-Date: 2023-12-18 09:27-0800\n"
+"Project-Id-Version: sandpaper 0.16.1.9000\n"
+"POT-Creation-Date: 2023-12-19 09:37-0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -10,354 +10,354 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: utils-translate.R:12
+#: utils-translate.R:74
msgid "Skip to main content"
msgstr ""
-#: utils-translate.R:13
+#: utils-translate.R:75
msgid "Pre-Alpha"
msgstr ""
-#: utils-translate.R:14
+#: utils-translate.R:76
msgid ""
"This lesson is in the pre-alpha phase, which means that it is in early "
"development, but has not yet been taught."
msgstr ""
-#: utils-translate.R:15
+#: utils-translate.R:77
msgid ""
"This lesson is in the alpha phase, which means that it has been taught once "
"and lesson authors are iterating on feedback."
msgstr ""
-#: utils-translate.R:16
+#: utils-translate.R:78
msgid "Alpha"
msgstr ""
-#: utils-translate.R:17
+#: utils-translate.R:79
msgid ""
"This lesson is in the beta phase, which means that it is ready for teaching "
"by instructors outside of the original author team."
msgstr ""
-#: utils-translate.R:18
+#: utils-translate.R:80
msgid "Beta"
msgstr ""
-#: utils-translate.R:19
+#: utils-translate.R:81
msgid "This lesson has passed peer review."
msgstr ""
-#: utils-translate.R:20
+#: utils-translate.R:82
msgid "Instructor View"
msgstr ""
-#: utils-translate.R:21
+#: utils-translate.R:83
msgid "Learner View"
msgstr ""
-#: utils-translate.R:22
+#: utils-translate.R:84
msgid "Main Navigation"
msgstr ""
-#: utils-translate.R:23
+#: utils-translate.R:85
msgid "Toggle Navigation"
msgstr ""
-#: utils-translate.R:24
+#: utils-translate.R:86
msgid "Menu"
msgstr ""
-#: utils-translate.R:25
+#: utils-translate.R:87
msgid "search button"
msgstr ""
-#: utils-translate.R:26
+#: utils-translate.R:88
msgid "Setup"
msgstr ""
-#: utils-translate.R:27
+#: utils-translate.R:89
msgid "Key Points"
msgstr ""
-#: utils-translate.R:28
+#: utils-translate.R:90
msgid "Instructor Notes"
msgstr ""
-#: utils-translate.R:29
+#: utils-translate.R:91
msgid "Glossary"
msgstr ""
-#: utils-translate.R:30
+#: utils-translate.R:92
msgid "Learner Profiles"
msgstr ""
-#: utils-translate.R:31
+#: utils-translate.R:93
msgid "More"
msgstr ""
-#: utils-translate.R:32
+#: utils-translate.R:94
msgid "Search"
msgstr ""
-#: utils-translate.R:33
+#: utils-translate.R:95
msgid "Lesson Progress"
msgstr ""
-#: utils-translate.R:35
+#: utils-translate.R:97
msgid "close menu"
msgstr ""
-#: utils-translate.R:36
+#: utils-translate.R:98
msgid "EPISODES"
msgstr ""
-#: utils-translate.R:37
+#: utils-translate.R:99
msgid "Home"
msgstr ""
-#: utils-translate.R:38
+#: utils-translate.R:100
msgid "Home Page Navigation"
msgstr ""
-#: utils-translate.R:39
+#: utils-translate.R:101
msgid "RESOURCES"
msgstr ""
-#: utils-translate.R:40
+#: utils-translate.R:102
msgid "Extract All Images"
msgstr ""
-#: utils-translate.R:41
+#: utils-translate.R:103
msgid "See all in one page"
msgstr ""
-#: utils-translate.R:42
+#: utils-translate.R:104
msgid "Download Lesson Handout"
msgstr ""
-#: utils-translate.R:43
+#: utils-translate.R:105
msgid "Export Chapter Slides"
msgstr ""
-#: utils-translate.R:45
+#: utils-translate.R:107
msgid "Previous and Next Chapter"
msgstr ""
-#: utils-translate.R:46
+#: utils-translate.R:108
msgid "Previous"
msgstr ""
-#: utils-translate.R:47
+#: utils-translate.R:109
msgid "Estimated time: {icons$clock} {minutes} minutes"
msgstr ""
-#: utils-translate.R:48
+#: utils-translate.R:110
msgid "Next"
msgstr ""
-#: utils-translate.R:49
+#: utils-translate.R:111
msgid "Next Chapter"
msgstr ""
-#: utils-translate.R:50
+#: utils-translate.R:112
msgid "Last updated on {updated}"
msgstr ""
-#: utils-translate.R:51
+#: utils-translate.R:113
msgid "Edit this page"
msgstr ""
-#: utils-translate.R:52 utils-translate.R:73
+#: utils-translate.R:114 utils-translate.R:135
msgid "Expand All Solutions"
msgstr ""
-#: utils-translate.R:54
+#: utils-translate.R:116
msgid "Setup Instructions"
msgstr ""
-#: utils-translate.R:55
+#: utils-translate.R:117
msgid "Download files required for the lesson"
msgstr ""
-#: utils-translate.R:56
+#: utils-translate.R:118
msgid ""
"The actual schedule may vary slightly depending on the topics and exercises "
"chosen by the instructor."
msgstr ""
-#: utils-translate.R:58
+#: utils-translate.R:120
msgid "Back To Top"
msgstr ""
-#: utils-translate.R:59
+#: utils-translate.R:121
msgid "<(Back)> To Top"
msgstr ""
-#: utils-translate.R:60
+#: utils-translate.R:122
msgid "This lesson is subject to the <(Code of Conduct)>"
msgstr ""
-#: utils-translate.R:61
+#: utils-translate.R:123
msgid "Code of Conduct"
msgstr ""
-#: utils-translate.R:62
+#: utils-translate.R:124
msgid "Edit on GitHub"
msgstr ""
-#: utils-translate.R:63
+#: utils-translate.R:125
msgid "Contributing"
msgstr ""
-#: utils-translate.R:64
+#: utils-translate.R:126
msgid "Source"
msgstr ""
-#: utils-translate.R:65
+#: utils-translate.R:127
msgid "Cite"
msgstr ""
-#: utils-translate.R:66
+#: utils-translate.R:128
msgid "Contact"
msgstr ""
-#: utils-translate.R:67
+#: utils-translate.R:129
msgid "About"
msgstr ""
-#: utils-translate.R:68
+#: utils-translate.R:130
msgid "Materials licensed under {license} by {authors}"
msgstr ""
-#: utils-translate.R:69
+#: utils-translate.R:131
msgid "Template licensed under <(CC-BY 4.0)> by {template_authors}"
msgstr ""
-#: utils-translate.R:70
+#: utils-translate.R:132
msgid "The Carpentries"
msgstr ""
-#: utils-translate.R:71
+#: utils-translate.R:133
msgid "Built with {sandpaper_link}, {pegboard_link}, and {varnish_link}"
msgstr ""
-#: utils-translate.R:74
+#: utils-translate.R:136
msgid "Collapse All Solutions"
msgstr ""
-#: utils-translate.R:75
+#: utils-translate.R:137
msgid "Collapse"
msgstr ""
-#: utils-translate.R:76
+#: utils-translate.R:138
msgid "Episodes"
msgstr ""
-#: utils-translate.R:78
+#: utils-translate.R:140
msgid "Give Feedback"
msgstr ""
-#: utils-translate.R:79
+#: utils-translate.R:141
msgid "Learn More"
msgstr ""
-#: utils-translate.R:85
+#: utils-translate.R:147
msgid "OUTPUT"
msgstr ""
-#: utils-translate.R:86
+#: utils-translate.R:148
msgid "WARNING"
msgstr ""
-#: utils-translate.R:87
+#: utils-translate.R:149
msgid "ERROR"
msgstr ""
-#: utils-translate.R:89
+#: utils-translate.R:151
msgid "Overview"
msgstr ""
-#: utils-translate.R:90
+#: utils-translate.R:152
msgid "Questions"
msgstr ""
-#: utils-translate.R:91
+#: utils-translate.R:153
msgid "Objectives"
msgstr ""
-#: utils-translate.R:92
+#: utils-translate.R:154
msgid "Callout"
msgstr ""
-#: utils-translate.R:93
+#: utils-translate.R:155
msgid "Challenge"
msgstr ""
-#: utils-translate.R:94
+#: utils-translate.R:156
msgid "Prerequisite"
msgstr ""
-#: utils-translate.R:95
+#: utils-translate.R:157
msgid "Checklist"
msgstr ""
-#: utils-translate.R:96
+#: utils-translate.R:158
msgid "Discussion"
msgstr ""
-#: utils-translate.R:97
+#: utils-translate.R:159
msgid "Testimonial"
msgstr ""
-#: utils-translate.R:100
+#: utils-translate.R:162
msgid "Show me the solution"
msgstr ""
-#: utils-translate.R:101
+#: utils-translate.R:163
msgid "Give me a hint"
msgstr ""
-#: utils-translate.R:102
+#: utils-translate.R:164
msgid "Show details"
msgstr ""
-#: utils-translate.R:103
+#: utils-translate.R:165
msgid "Instructor Note"
msgstr ""
-#: utils-translate.R:105
+#: utils-translate.R:167
msgid "Summary and Setup"
msgstr ""
-#: utils-translate.R:106
+#: utils-translate.R:168
msgid "Summary and Schedule"
msgstr ""
-#: utils-translate.R:107
+#: utils-translate.R:169
msgid "All in One View"
msgstr ""
-#: utils-translate.R:108
+#: utils-translate.R:170
msgid "Page not found"
msgstr ""
-#: utils-translate.R:109
+#: utils-translate.R:171
msgid "All Images"
msgstr ""
-#: utils-translate.R:111
+#: utils-translate.R:173
msgid "anchor"
msgstr ""
-#: utils-translate.R:112
+#: utils-translate.R:174
msgid "Figure {element}"
msgstr ""
-#: utils-translate.R:113
+#: utils-translate.R:175
msgid "Image {i} of {n}: {sQuote(txt)}"
msgstr ""
-#: utils-translate.R:114
+#: utils-translate.R:176
msgid "Finish"
msgstr ""
diff --git a/tests/testthat/test-build_html.R b/tests/testthat/test-build_html.R
index 654f9a89..bc2d03cf 100644
--- a/tests/testthat/test-build_html.R
+++ b/tests/testthat/test-build_html.R
@@ -80,9 +80,6 @@ test_that("(#536) SANDPAPER_SITE envvar works as expected", {
expect_false(fs::file_exists(orig_profiles_learner))
expect_false(fs::file_exists(orig_profiles_instructor))
- # needed to ensure the global translations are implemented.
- set_language("en")
-
# after build, only the files constrolled by the SANDPAPER_SITE envvar should
# exist, but the ones in the default site should not exist.
build_profiles(new_pkg, quiet = TRUE)
@@ -106,9 +103,6 @@ test_that("[build_home()] works independently", {
fs::file_copy(fs::path(res, "index.md"), built_dir)
fs::file_copy(fs::path(res, "learners", "setup.md"), built_dir)
- # needed to ensure the global translations are implemented.
- set_language("en")
-
build_home(pkg, quiet = TRUE,
next_page = fs::path(res, "episodes", "introduction.Rmd")
)
@@ -182,9 +176,6 @@ test_that("[build_profiles()] works independently", {
expect_false(fs::file_exists(fs::path(pkg$dst_path, "profiles.html")))
expect_false(fs::file_exists(fs::path(pkg$dst_path, "instructor", "profiles.html")))
- # needed to ensure the global translations are implemented.
- set_language("en")
-
build_profiles(pkg, quiet = TRUE)
expect_true(fs::file_exists(fs::path(pkg$dst_path, "profiles.html")))
expect_true(fs::file_exists(fs::path(pkg$dst_path, "instructor", "profiles.html")))
diff --git a/tests/testthat/test-translate.R b/tests/testthat/test-translate.R
deleted file mode 100644
index 03209fe2..00000000
--- a/tests/testthat/test-translate.R
+++ /dev/null
@@ -1,235 +0,0 @@
-# Generate temporary lesson and set `lang: ja` in config.yaml
-tmp <- res <- restore_fixture()
-config_path <- fs::path(tmp, "config.yaml")
-config <- yaml::read_yaml(config_path)
-config$lang <- "ja"
-yaml::write_yaml(config, config_path)
-sitepath <- fs::path(tmp, "site", "docs")
-
-test_that("set_language() uses english by default", {
-
- os <- tolower(Sys.info()[["sysname"]])
- ver <- getRversion()
- skip_if(os == "windows" && ver < "4.2")
-
- # Before anything happens, the translations should match the source
- expect_equal(these$translations$src$computed, these$translations$computed)
- expect_equal(these$translations$src$varnish, these$translations$varnish)
-
- # default is english
- set_language()
-
- # If the translations are set to english, the source should continue to match
- expect_equal(these$translations$src$computed, these$translations$computed)
- expect_equal(these$translations$src$varnish, these$translations$varnish)
-
- # confirm a specific source element
- src <- these$translations$src$computed$OUTPUT
- expect_equal(these$translations$computed$OUTPUT, src)
-
- # set to japanese and it becomes different
- set_language("ja")
- expect_failure({
- expect_equal(these$translations$src$computed, these$translations$computed)
- })
- expect_failure({
- expect_equal(these$translations$src$varnish, these$translations$varnish)
- })
- OUTJA <- these$translations$computed$OUTPUT
- expect_failure(expect_equal(OUTJA, src))
-
- # unknown language will not switch the current language
- suppressMessages(expect_message(set_language("xx"), "languages"))
- expect_equal(these$translations$computed$OUTPUT, OUTJA)
-
- # set back to english (default)
- set_language()
- expect_equal(these$translations$computed$OUTPUT, src)
-
-})
-
-
-test_that("set_language() can use country codes", {
-
- os <- tolower(Sys.info()[["sysname"]])
- ver <- getRversion()
- skip_if(os == "windows" && ver < "4.2")
-
- src <- these$translations$src$computed$OUTPUT
- expect_silent(set_language("es_AR"))
- OUTAR <- these$translations$computed$OUTPUT
- expect_false(identical(OUTAR, src))
-
- # the country codes will fall back to language code if they don't exist
- expect_silent(set_language("es"))
- expect_equal(these$translations$computed$OUTPUT, OUTAR)
-
-})
-
-
-test_that("is_known_language returns a warning for an unknown language", {
-
- os <- tolower(Sys.info()[["sysname"]])
- ver <- getRversion()
- skip_if(os == "windows" && ver < "4.2")
-
- expect_true(is_known_language("ja"))
- expect_false(is_known_language("xx"))
- suppressMessages({
- expect_message({
- expect_false(is_known_language("xx", warn = TRUE))
- }, "languages", label = "is_known_language(warn = TRUE)")
- })
-
-})
-
-
-test_that("Lessons can be translated with lang setting", {
-
- # NOTE: this requires the expect_set_translated() function defined in
- # tests/testthat/helper-translate.R
-
- skip_if_not(rmarkdown::pandoc_available("2.11"))
-
- os <- tolower(Sys.info()[["sysname"]])
- ver <- getRversion()
- skip_if(os == "windows" && ver < "4.2")
-
- # Build lesson
- suppressMessages(build_lesson(tmp, preview = FALSE, quiet = TRUE))
-
-
- # Home Page ------------------------------------------------------
- # Testing both learner and instructor versions of this page
- xml <- xml2::read_html(fs::path(sitepath, "index.html"))
- instruct <- xml2::read_html(fs::path(sitepath, "instructor/index.html"))
- # language should be set to japanese
- expect_equal(xml2::xml_attr(xml, "lang"), "ja")
- to_main <- xml2::xml_find_first(xml, "//a[@href='#main-content']")
- ito_main <- xml2::xml_find_first(instruct, "//a[@href='#main-content']")
- expect_set_translated(to_main, "Skip to main content")
- expect_set_translated(ito_main, "Skip to main content")
-
- expect_equal(xml2::xml_attr(instruct, "lang"), "ja")
- expect_title_translated(xml, "Summary and Setup")
- expect_title_translated(instruct, "Summary and Schedule")
-
- # Extract first header (Summary and Setup) from index
- h1_xpath <- "//h1[@class='schedule-heading']"
- h1_header <- xml2::xml_find_all(xml, h1_xpath)
- expect_set_translated(h1_header, "Summary and Setup")
- ih1_header <- xml2::xml_find_all(instruct, h1_xpath)
- expect_set_translated(ih1_header, "Summary and Schedule")
-
- # Schedule for instructor view ends with "Finish"
- final_cell <- xml2::xml_find_first(instruct, "//tr[last()]/td[2]")
- expect_set_translated(final_cell, "Finish")
-
- # Navbar has expected text
- nav_xpath <- "//a[starts-with(@class,'nav-link')]"
- nav_links <- xml2::xml_find_all(xml, nav_xpath)
- expect_set_translated(nav_links,
- c("Key Points", "Glossary", "Learner Profiles")
- )
- inav_links <- xml2::xml_find_all(instruct, nav_xpath)
- expect_set_translated(inav_links,
- c("Key Points", "Instructor Notes", "Extract All Images")
- )
-
- # aria labels should be translated
- aria_text <- c(
- "Main Navigation",
- "Toggle Navigation",
- "Search",
- "search button",
- "Lesson Progress",
- "close menu",
- "Next Chapter",
- "anchor",
- "Back To Top"
- )
- aria_labels <- xml2::xml_find_all(xml, ".//@aria-label")
- iaria_labels <- xml2::xml_find_all(instruct, ".//@aria-label")
- expect_set_translated(aria_labels, aria_text)
- expect_set_translated(iaria_labels, aria_text)
-
-
- # GENERATED PAGES ------------------------------------------------
- # These pages should have translated headers and title elements
- inst_notes_path <- fs::path(sitepath, "instructor/instructor-notes.html")
- inst_notes <- xml2::read_html(inst_notes_path)
- expect_equal(xml2::xml_attr(inst_notes, "lang"), "ja")
- expect_h1_translated(inst_notes, "Instructor Notes")
- expect_title_translated(inst_notes, "Instructor Notes")
-
- profiles <- xml2::read_html(fs::path(sitepath, "profiles.html"))
- expect_equal(xml2::xml_attr(profiles, "lang"), "ja")
- expect_h1_translated(profiles, "Learner Profiles")
- expect_title_translated(profiles, "Learner Profiles")
-
- fof <- xml2::read_html(fs::path(sitepath, "404.html"))
- expect_equal(xml2::xml_attr(fof, "lang"), "ja")
- expect_h1_translated(fof, "Page not found")
- expect_title_translated(fof, "Page not found")
-
- imgs <- xml2::read_html(fs::path(sitepath, "instructor/images.html"))
- expect_equal(xml2::xml_attr(imgs, "lang"), "ja")
- expect_title_translated(imgs, "All Images")
-
-
- # Episode elements -------------------------------------------------
- # We use here the Instructor view because it is more fully featured
- # NOTE: we expect this to be the first episode after the home page
- xml <- xml2::read_html(fs::path(sitepath, "instructor", "introduction.html"))
- expect_equal(xml2::xml_attr(xml, "lang"), "ja")
- to_main <- xml2::xml_find_first(xml, "//a[@href='#main-content']")
- expect_set_translated(to_main, "Skip to main content")
- previous <- xml2::xml_find_all(xml, "//a[@class='chapter-link']")
- expect_set_translated(previous, c("Home", "Previous"))
-
- # navbar has expected text
- nav_links <- xml2::xml_find_all(xml, "//a[starts-with(@class,'nav-link')]")
- expect_set_translated(nav_links,
- c("Key Points", "Instructor Notes", "Extract All Images")
- )
-
- # aria labels should be translated
- aria_text <- c(
- "Main Navigation",
- "Toggle Navigation",
- "Search",
- "search button",
- "Lesson Progress",
- "close menu",
- "Previous and Next Chapter",
- "anchor",
- "Back To Top"
- )
- aria_labels <- xml2::xml_find_all(xml, ".//@aria-label")
- expect_set_translated(aria_labels, aria_text)
-
- # overview, objectives, and questions
- overview_card <- xml2::xml_find_first(xml, ".//div[@class='overview card']")
- over_heads <- xml2::xml_find_all(overview_card, ".//h2 | .//h3")
- expect_set_translated(over_heads, c("Overview", "Questions", "Objectives"))
-
- # Keypoints are always the last block and should be auto-translated
- xpath_keypoints <- ".//div[@class='callout keypoints']//h3[@class='callout-title']"
- keypoints <- xml2::xml_find_first(xml, xpath_keypoints)
- expect_set_translated(keypoints, "Key Points")
-
- # Instructor note headings should be translated
- xpath_instructor <- ".//div[@class='accordion-item']/button/h3"
- instructor_note <- xml2::xml_find_all(xml, xpath_instructor)
- expect_set_translated(instructor_note, "Instructor Note")
-
- # solution headings should be translated
- xpath_solution <- ".//div[@class='accordion-item']/button/h4"
- solution <- xml2::xml_find_all(xml, xpath_solution)
- # take the last solution block because that's the one that does not have
- # a title.
- solution <- solution[[length(solution)]]
-
- expect_set_translated(solution, "Show me the solution")
-
-})
diff --git a/tests/testthat/test-utils-translate.R b/tests/testthat/test-utils-translate.R
new file mode 100644
index 00000000..c8d3692e
--- /dev/null
+++ b/tests/testthat/test-utils-translate.R
@@ -0,0 +1,362 @@
+# Generate temporary lesson and set `lang: ja` in config.yaml
+tmp <- res <- restore_fixture()
+config_path <- fs::path(tmp, "config.yaml")
+config <- yaml::read_yaml(config_path)
+config$lang <- "ja"
+yaml::write_yaml(config, config_path)
+sitepath <- fs::path(tmp, "site", "docs")
+
+# A Note on the conventions of this test file
+# -------------------------------------------
+#
+# The majority of the tests in this file are testing on the rendered version
+# of the lesson that is created above. The lesson is built and then all of the
+# tests for specific keys are run after it. You can find where it builds by
+# searching for a series of equals signs: =======
+#
+# The `helper-translate.R` file contains three functions. These functions will
+# actively test the `tr_()` function, which acts on the VALUES and they test
+# that the text in an HTML node matches the translated text AND that it DOES NOT
+# match the English text.
+#
+# - expect_set_translated() will take in an HTML node and the values to test
+# against a known language (ja)
+# - expect_title_translated() does the same, except it will test that the
+# element is translated, which is useful for generated pages
+# - expect_h1_tranlsated() does the same, except it tests for the H1 element,
+# which is useful for generated pages that have h1 headings.
+#
+# When we test translations, it's important to use the KEYS and not the VALUES
+# for the translations, which will come from the `tr_src()` function. The early
+# tests will confirm that the `tr_src()` function contains the source strings
+# and the `tr_varnish()` and `tr_computed()` functions contain the translated
+# strings.
+#
+# good:
+# expect_set_translated(node,
+# tr_src("varnish", "LearnerProfiles")
+# )
+# expect_set_translated(nodeset,
+# c(
+# tr_src("varnish", "KeyPoints"),
+# tr_src("varnish", "Glossary"),
+# tr_src("varnish", "LearnerProfiles")
+# )
+# )
+# bad:
+# expect_set_translated(node, "Learner Profiles")
+# expect_set_translated(nodeset,
+# c("Key Points", "Glossary", "Learner Profiles")
+# )
+#
+# The reason for this convention is two-fold:
+#
+# 1. using tr_src(collection, key) allows us to confirm that a given key is
+# found in a specific collection.
+# 2. we can change the values and confirm that the tests work without changing
+# the tests.
+#
+# That's it. Happy testing, don't die!
+
+test_that("tr_ helpers will extract the source", {
+
+ expect_equal(these$translations$src$computed, tr_src("computed"))
+ expect_equal(these$translations$src$varnish, tr_src("varnish"))
+
+ # different collections should not be equivalent
+ expect_failure({
+ expect_equal(tr_src("varnish"), tr_src("computed"))
+ })
+})
+
+
+test_that("set_language() uses english by default and test helpers are valid", {
+
+ os <- tolower(Sys.info()[["sysname"]])
+ ver <- getRversion()
+ skip_if(os == "windows" && ver < "4.2")
+
+ # Before anything happens, the translations should match the source
+ expect_equal(tr_computed(), tr_src("computed"))
+ expect_equal(tr_varnish(), tr_src("varnish"))
+
+ # translations should not match their reciprocal
+ expect_failure({
+ expect_equal(tr_computed(), tr_src("varnish"))
+ })
+ expect_failure({
+ expect_equal(tr_varnish(), tr_src("computed"))
+ })
+
+ # default is english
+ set_language()
+
+ # If the translations are set to english, the source should continue to match
+ expect_equal(tr_computed(), tr_src("computed"))
+ expect_equal(tr_varnish(), tr_src("varnish"))
+
+ # confirm a specific source element
+ src <- tr_src("computed", "OUTPUT")
+ expect_equal(src, tr_computed("OUTPUT"))
+
+ # set to japanese and it becomes different
+ set_language("ja")
+ expect_failure({
+ expect_equal(tr_computed(), tr_src("computed"))
+ })
+ expect_failure({
+ expect_equal(tr_varnish(), tr_src("varnish"))
+ })
+ OUTJA <- tr_computed("OUTPUT")
+ expect_failure(expect_equal(OUTJA, src))
+
+ # unknown language will not switch the current language
+ suppressMessages(expect_message(set_language("xx"), "languages"))
+ expect_equal(tr_computed("OUTPUT"), OUTJA)
+
+ # set back to english (default)
+ set_language()
+ expect_equal(tr_computed("OUTPUT"), src)
+
+})
+
+
+test_that("set_language() can use country codes", {
+
+ os <- tolower(Sys.info()[["sysname"]])
+ ver <- getRversion()
+ skip_if(os == "windows" && ver < "4.2")
+
+ src <- tr_src("computed")$OUTPUT
+ expect_silent(set_language("es_AR"))
+ OUTAR <- tr_computed("OUTPUT")
+ expect_false(identical(OUTAR, src))
+
+ # the country codes will fall back to language code if they don't exist
+ expect_silent(set_language("es"))
+ expect_equal(tr_computed("OUTPUT"), OUTAR)
+
+})
+
+
+test_that("is_known_language returns a warning for an unknown language", {
+
+ os <- tolower(Sys.info()[["sysname"]])
+ ver <- getRversion()
+ skip_if(os == "windows" && ver < "4.2")
+
+ expect_true(is_known_language("ja"))
+ expect_false(is_known_language("xx"))
+ suppressMessages({
+ expect_message({
+ expect_false(is_known_language("xx", warn = TRUE))
+ }, "languages", label = "is_known_language(warn = TRUE)")
+ })
+
+})
+
+
+test_that("Lessons can be translated with lang setting", {
+
+ # NOTE: this requires the following functions defined in
+ # tests/testthat/helper-translate.R:
+ # - expect_set_translated()
+ # - expect_title_translated()
+ # - expect_h1_translated()
+
+ skip_if_not(rmarkdown::pandoc_available("2.11"))
+
+ os <- tolower(Sys.info()[["sysname"]])
+ ver <- getRversion()
+ skip_if(os == "windows" && ver < "4.2")
+
+ # Build lesson ===================================================
+ suppressMessages(build_lesson(tmp, preview = FALSE, quiet = TRUE))
+
+
+ # Home Page ------------------------------------------------------
+ # Testing both learner and instructor versions of this page
+ xml <- xml2::read_html(fs::path(sitepath, "index.html"))
+ instruct <- xml2::read_html(fs::path(sitepath, "instructor/index.html"))
+ # language should be set to japanese
+ expect_equal(xml2::xml_attr(xml, "lang"), "ja")
+ to_main <- xml2::xml_find_first(xml, "//a[@href='#main-content']")
+ ito_main <- xml2::xml_find_first(instruct, "//a[@href='#main-content']")
+ expect_set_translated(to_main,
+ tr_src("varnish", "SkipToMain")
+ )
+ expect_set_translated(ito_main,
+ tr_src("varnish", "SkipToMain")
+ )
+
+ expect_equal(xml2::xml_attr(instruct, "lang"), "ja")
+ expect_title_translated(xml,
+ tr_src("computed", "SummaryAndSetup")
+ )
+ expect_title_translated(instruct,
+ tr_src("computed", "SummaryAndSchedule")
+ )
+
+ # Extract first header (Summary and Setup) from index
+ h1_xpath <- "//h1[@class='schedule-heading']"
+ h1_header <- xml2::xml_find_all(xml, h1_xpath)
+ expect_set_translated(h1_header,
+ tr_src("computed", "SummaryAndSetup")
+ )
+ ih1_header <- xml2::xml_find_all(instruct, h1_xpath)
+ expect_set_translated(ih1_header,
+ tr_src("computed", "SummaryAndSchedule")
+ )
+
+ # Schedule for instructor view ends with "Finish"
+ final_cell <- xml2::xml_find_first(instruct, "//tr[last()]/td[2]")
+ expect_set_translated(final_cell,
+ tr_src("computed", "Finish")
+ )
+
+ # Navbar has expected text
+ nav_xpath <- "//a[starts-with(@class,'nav-link')]"
+ nav_links <- xml2::xml_find_all(xml, nav_xpath)
+ expect_set_translated(nav_links,
+ c(tr_src("varnish", "KeyPoints"),
+ tr_src("varnish", "Glossary"),
+ tr_src("varnish", "LearnerProfiles")
+ )
+ )
+ inav_links <- xml2::xml_find_all(instruct, nav_xpath)
+ expect_set_translated(inav_links,
+ c(tr_src("varnish", "KeyPoints"),
+ tr_src("varnish", "InstructorNotes"),
+ tr_src("varnish", "ExtractAllImages")
+ )
+ )
+
+ # aria labels should be translated
+ aria_text <- c(
+ tr_src("varnish", "MainNavigation"),
+ tr_src("varnish", "ToggleNavigation"),
+ tr_src("varnish", "Search"),
+ tr_src("varnish", "SearchButton"),
+ tr_src("varnish", "LessonProgress"),
+ tr_src("varnish", "CloseMenu"),
+ tr_src("varnish", "NextChapter"),
+ tr_src("computed", "Anchor"),
+ tr_src("varnish", "BackToTop")
+ )
+ aria_labels <- xml2::xml_find_all(xml, ".//@aria-label")
+ iaria_labels <- xml2::xml_find_all(instruct, ".//@aria-label")
+ expect_set_translated(aria_labels, aria_text)
+ expect_set_translated(iaria_labels, aria_text)
+
+
+ # GENERATED PAGES ------------------------------------------------
+ # These pages should have translated headers and title elements
+ inst_notes_path <- fs::path(sitepath, "instructor/instructor-notes.html")
+ inst_notes <- xml2::read_html(inst_notes_path)
+ expect_equal(xml2::xml_attr(inst_notes, "lang"), "ja")
+ expect_h1_translated(inst_notes,
+ tr_src("varnish", "InstructorNotes")
+ )
+ expect_title_translated(inst_notes,
+ tr_src("varnish", "InstructorNotes")
+ )
+
+ profiles <- xml2::read_html(fs::path(sitepath, "profiles.html"))
+ expect_equal(xml2::xml_attr(profiles, "lang"), "ja")
+ expect_h1_translated(profiles,
+ tr_src("varnish", "LearnerProfiles")
+ )
+ expect_title_translated(profiles,
+ tr_src("varnish", "LearnerProfiles")
+ )
+
+ fof <- xml2::read_html(fs::path(sitepath, "404.html"))
+ expect_equal(xml2::xml_attr(fof, "lang"), "ja")
+ expect_h1_translated(fof,
+ tr_src("computed", "PageNotFound")
+ )
+ expect_title_translated(fof,
+ tr_src("computed", "PageNotFound")
+ )
+
+ imgs <- xml2::read_html(fs::path(sitepath, "instructor/images.html"))
+ expect_equal(xml2::xml_attr(imgs, "lang"), "ja")
+ expect_title_translated(imgs,
+ tr_src("computed", "AllImages")
+ )
+
+
+ # Episode elements -------------------------------------------------
+ # We use here the Instructor view because it is more fully featured
+ # NOTE: we expect this to be the first episode after the home page
+ xml <- xml2::read_html(fs::path(sitepath, "instructor", "introduction.html"))
+ expect_equal(xml2::xml_attr(xml, "lang"), "ja")
+ to_main <- xml2::xml_find_first(xml, "//a[@href='#main-content']")
+ expect_set_translated(to_main, tr_src("varnish", "SkipToMain"))
+ previous <- xml2::xml_find_all(xml, "//a[@class='chapter-link']")
+ expect_set_translated(previous, c(
+ tr_src("varnish", "Home"),
+ tr_src("varnish", "Previous")
+ )
+ )
+
+ # navbar has expected text
+ nav_links <- xml2::xml_find_all(xml, "//a[starts-with(@class,'nav-link')]")
+ expect_set_translated(nav_links,
+ c(tr_src("varnish", "KeyPoints"),
+ tr_src("varnish", "InstructorNotes"),
+ tr_src("varnish", "ExtractAllImages")
+ )
+ )
+
+ # aria labels should be translated
+ aria_text <- c(
+ tr_src("varnish", "MainNavigation"),
+ tr_src("varnish", "ToggleNavigation"),
+ tr_src("varnish", "Search"),
+ tr_src("varnish", "SearchButton"),
+ tr_src("varnish", "LessonProgress"),
+ tr_src("varnish", "CloseMenu"),
+ tr_src("varnish", "PreviousAndNext"),
+ tr_src("computed", "Anchor"),
+ tr_src("varnish", "BackToTop")
+ )
+ aria_labels <- xml2::xml_find_all(xml, ".//@aria-label")
+ expect_set_translated(aria_labels, aria_text)
+
+ # overview, objectives, and questions
+ overview_card <- xml2::xml_find_first(xml, ".//div[@class='overview card']")
+ over_heads <- xml2::xml_find_all(overview_card, ".//h2 | .//h3")
+ expect_set_translated(over_heads,
+ c(tr_src("computed", "Overview"),
+ tr_src("computed", "Questions"),
+ tr_src("computed", "Objectives")
+ )
+ )
+
+ # Keypoints are always the last block and should be auto-translated
+ xpath_keypoints <- ".//div[@class='callout keypoints']//h3[@class='callout-title']"
+ keypoints <- xml2::xml_find_first(xml, xpath_keypoints)
+ expect_set_translated(keypoints,
+ tr_src("computed", "Keypoints")
+ )
+
+ # Instructor note headings should be translated
+ xpath_instructor <- ".//div[@class='accordion-item']/button/h3"
+ instructor_note <- xml2::xml_find_all(xml, xpath_instructor)
+ expect_set_translated(instructor_note,
+ tr_src("computed", "Instructor Note")
+ )
+
+ # solution headings should be translated
+ xpath_solution <- ".//div[@class='accordion-item']/button/h4"
+ solution <- xml2::xml_find_all(xml, xpath_solution)
+ # take the last solution block because that's the one that does not have
+ # a title.
+ solution <- solution[[length(solution)]]
+
+ expect_set_translated(solution,
+ tr_src("computed", "Show me the solution")
+ )
+
+})
diff --git a/vignettes/translations.Rmd b/vignettes/translations.Rmd
index dbe092c4..308a2378 100644
--- a/vignettes/translations.Rmd
+++ b/vignettes/translations.Rmd
@@ -149,9 +149,11 @@ with_language("xx", {
})
```
-To make translation keys easier to detect, a convenience function, `tr_()` has
-been defined, so if you want to find the context for a given translation key,
-you can find it by searching the source code for `tr_`.
+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_`.
### Special syntax for translators