Skip to content

Commit 7648a1f

Browse files
authored
Allow feedback on unparsable unicode characters to render without i18next (#765)
* fix(unparsable_unicode_message): pre-interpolate message so feedback is comprehensible when `i18next` is unavailable * docs: update NEWS * docs: update documentation * refactor(unparsable_unicode_message): use `sub()` rather than `glue()` to handle interpolation
1 parent 86b53df commit 7648a1f

File tree

6 files changed

+53
-49
lines changed

6 files changed

+53
-49
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,5 +72,5 @@ Config/Needs/coverage: covr
7272
Config/Needs/website: pkgdown, tidyverse/tidytemplate
7373
Encoding: UTF-8
7474
Roxygen: list(markdown = TRUE)
75-
RoxygenNote: 7.2.1
75+
RoxygenNote: 7.2.3
7676
SystemRequirements: pandoc (>= 1.14) - http://pandoc.org

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
- The embedded Ace editor used in learnr exercises now defaults to a tab width of 2, aligning with the Tidyverse style guide (#761).
66

7+
- Add a fallback to generate a comprehensible English feedback message for code that fails to parse because it contains non-ASCII characters. Previously, if i18next was unavailable, the feedback would contain uninterpolated i18next markup. Now the feedback is pre-interpolated so students will always see a comprehensible message (#765).
8+
79
# learnr 0.11.2
810

911
- Fixed an issue that prevented htmlwidgets from working in exercise code unless similar widgets were added to the tutorial prose (thanks @munoztd0 #744, #745).

R/exercise.R

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,20 +1039,32 @@ exercise_check_unparsable_unicode <- function(exercise, error_message) {
10391039
)
10401040
}
10411041

1042-
unparsable_unicode_message <- function(i18n_key, code, line, pattern, replacement_pattern = NULL) {
1042+
unparsable_unicode_message <- function(
1043+
i18n_key, code, line, pattern, replacement_pattern = NULL
1044+
) {
10431045
code <- unlist(strsplit(code, "\n"))[[line]]
10441046

10451047
character <- str_extract(code, pattern)
10461048
highlighted_code <- exercise_highlight_unparsable_unicode(code, pattern, line)
10471049

1048-
suggestion <- NULL
1049-
if (!is.null(replacement_pattern)) {
1050-
suggestion <- html_code_block(str_replace_all(code, replacement_pattern))
1050+
suggestion <- if (!is.null(replacement_pattern)) {
1051+
html_code_block(str_replace_all(code, replacement_pattern))
1052+
} else {
1053+
NULL
1054+
}
1055+
1056+
code <- exercise_highlight_unparsable_unicode(code, pattern, line)
1057+
1058+
text <- i18n_translations()$en$translation$text[[i18n_key]]
1059+
text <- sub("{{character}}", character, text, fixed = TRUE)
1060+
text <- sub("{{code}}", highlighted_code, text, fixed = TRUE)
1061+
if (!is.null(suggestion)) {
1062+
text <- sub("{{suggestion}}", suggestion, text, fixed = TRUE)
10511063
}
10521064

10531065
i18n_div(
10541066
paste0("text.", i18n_key),
1055-
HTML(i18n_translations()$en$translation$text[[i18n_key]]),
1067+
HTML(text),
10561068
opts = list(
10571069
character = character,
10581070
code = highlighted_code,

man/learnr-package.Rd

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/tutorial.Rd

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test-exercise.R

Lines changed: 26 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,52 +1171,42 @@ test_that("Errors with global setup code result in an internal error", {
11711171
test_that("evaluate_exercise() returns message for unparsable non-ASCII code", {
11721172
skip_if_not_pandoc("1.14")
11731173

1174+
expect_unparsable_message <- function(user_code, problem, key) {
1175+
ex <- mock_exercise(user_code = user_code)
1176+
feedback <- evaluate_exercise(ex, new.env())$feedback
1177+
expect_equal(feedback, exercise_check_code_is_parsable(ex)$feedback)
1178+
expect_match(feedback$message, regexp = key, fixed = TRUE)
1179+
for (character in problem) {
1180+
expect_match(feedback$message, regexp = character, fixed = TRUE)
1181+
}
1182+
}
1183+
11741184
# Curly double quotes
1175-
ex <- mock_exercise(
1176-
user_code = "str_detect(\u201ctest\u201d, \u201ct.+t\u201d)"
1177-
)
1178-
result <- evaluate_exercise(ex, new.env())
1179-
expect_equal(result$feedback, exercise_check_code_is_parsable(ex)$feedback)
1180-
expect_match(result$feedback$message, "text.unparsablequotes")
1181-
expect_match(
1182-
result$feedback$message,
1183-
i18n_translations()$en$translation$text$unparsablequotes,
1184-
fixed = TRUE
1185+
expect_unparsable_message(
1186+
"str_detect(\u201ctest\u201d, \u201ct.+t\u201d)",
1187+
problem = c("\u201c", "\u201d"),
1188+
key = "text.unparsablequotes"
11851189
)
11861190

11871191
# Curly single quotes
1188-
ex <- mock_exercise(
1189-
user_code = "str_detect(\u2018test\u2019, \u2018t.+t\u2019)"
1190-
)
1191-
result <- evaluate_exercise(ex, new.env())
1192-
expect_equal(result$feedback, exercise_check_code_is_parsable(ex)$feedback)
1193-
expect_match(result$feedback$message, "text.unparsablequotes")
1194-
expect_match(
1195-
result$feedback$message,
1196-
i18n_translations()$en$translation$text$unparsablequotes,
1197-
fixed = TRUE
1192+
expect_unparsable_message(
1193+
"str_detect(\u2018test\u2019, \u2018t.+t\u2019)",
1194+
problem = c("\u2018", "\u2019"),
1195+
key = "text.unparsablequotes"
11981196
)
11991197

12001198
# En dash
1201-
ex <- mock_exercise(user_code = "63 \u2013 21")
1202-
result <- evaluate_exercise(ex, new.env())
1203-
expect_equal(result$feedback, exercise_check_code_is_parsable(ex)$feedback)
1204-
expect_match(result$feedback$message, "text.unparsableunicodesuggestion")
1205-
expect_match(
1206-
result$feedback$message,
1207-
i18n_translations()$en$translation$text$unparsableunicodesuggestion,
1208-
fixed = TRUE
1199+
expect_unparsable_message(
1200+
"63 \u2013 21",
1201+
problem = "\u2013",
1202+
key = "text.unparsableunicodesuggestion"
12091203
)
12101204

12111205
# Plus-minus sign
1212-
ex <- mock_exercise(user_code = "63 \u00b1 21")
1213-
result <- evaluate_exercise(ex, new.env())
1214-
expect_equal(result$feedback, exercise_check_code_is_parsable(ex)$feedback)
1215-
expect_match(result$feedback$message, "text.unparsableunicode")
1216-
expect_match(
1217-
result$feedback$message,
1218-
i18n_translations()$en$translation$text$unparsableunicode,
1219-
fixed = TRUE
1206+
expect_unparsable_message(
1207+
"63 \u00b1 21",
1208+
problem = "\u00b1",
1209+
key = "text.unparsableunicode"
12201210
)
12211211
})
12221212

0 commit comments

Comments
 (0)