Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added lang attribute for accessibility and search-engine parsers #2920

Closed
wants to merge 19 commits into from
Closed
6 changes: 6 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
shiny 1.5.0.9000
================

## Full changelog

### Accessibility

* Added [bootstrap accessibility plugin](https://github.com/paypal/bootstrap-accessibility-plugin) under the hood to improve accessibility of shiny apps for screen-reader and keyboard users: the enhancements include better navigations for alert, tooltip, popover, modal dialog, dropdown, tab Panel, collapse, and carousel elements. (#2911)
Expand All @@ -14,6 +16,8 @@ shiny 1.5.0.9000

* Closed #2847: `selectInput()` is reasonably accessible for screen readers even when `selectize` option is set to TRUE. To improve `selectize.js` accessibility, We have added [selectize-plugin-a11y](https://github.com/SLMNBJ/selectize-plugin-a11y) by default. (#2993)

* Closed #2844: Added `lang` argument to ui `*Page()` functions (e.g., `fluidPage`, `bootstrapPage`) that specifies document-level language within the app for the accessibility of screen readers and search-engine parsers. By default, it is set to empty string which is commonly recognized as a browser's default locale. (#2920)

### Minor new features and improvements

* When UI is specified as a function (e.g. `ui <- function(req) { ... }`), the response can now be an HTTP response as returned from the (newly exported) `httpResponse()` function. (#2970)
Expand All @@ -22,6 +26,8 @@ shiny 1.5.0.9000

* Closed #2972: `runExample()` now supports the `shiny.port` option (thanks to @ColinFay). (#2982)

* Added the `lang` argument to `shinyApp()` that specifies document-level language within the app for the accessibility of screen readers and search-engine parsers [#2844](https://github.com/rstudio/shiny/issues/2844).

### Bug fixes

* Fixed #2859: `renderPlot()` wasn't correctly setting `showtext::showtext_opts()`'s `dpi` setting with the correct resolution on high resolution displays; which means, if the font was rendered by showtext, font sizes would look smaller than they should on such displays. (#2941)
Expand Down
12 changes: 8 additions & 4 deletions R/bootstrap-layout.R
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#' @param theme Alternative Bootstrap stylesheet (normally a css file within the
#' www directory). For example, to use the theme located at
#' `www/bootstrap.css` you would use `theme = "bootstrap.css"`.
#' @param lang ISO 639-1 language code used within the shiny app. Default is set to empty value.
#'
#' @return A UI defintion that can be passed to the [shinyUI] function.
#'
Expand Down Expand Up @@ -87,11 +88,12 @@
#' }
#' @rdname fluidPage
#' @export
fluidPage <- function(..., title = NULL, responsive = NULL, theme = NULL) {
fluidPage <- function(..., title = NULL, responsive = NULL, theme = NULL, lang = NULL) {
bootstrapPage(div(class = "container-fluid", ...),
title = title,
responsive = responsive,
theme = theme)
theme = theme,
lang = lang)
}


Expand All @@ -118,6 +120,7 @@ fluidRow <- function(...) {
#' @param theme Alternative Bootstrap stylesheet (normally a css file within the
#' www directory). For example, to use the theme located at
#' `www/bootstrap.css` you would use `theme = "bootstrap.css"`.
#' @param lang ISO 639-1 language code used within the shiny app. Default is set to empty value.
jooyoungseo marked this conversation as resolved.
Show resolved Hide resolved
#'
#' @return A UI defintion that can be passed to the [shinyUI] function.
#'
Expand Down Expand Up @@ -156,11 +159,12 @@ fluidRow <- function(...) {
#'
#' @rdname fixedPage
#' @export
fixedPage <- function(..., title = NULL, responsive = NULL, theme = NULL) {
fixedPage <- function(..., title = NULL, responsive = NULL, theme = NULL, lang = NULL) {
bootstrapPage(div(class = "container", ...),
title = title,
responsive = responsive,
theme = theme)
theme = theme,
lang = lang)
}

#' @rdname fixedPage
Expand Down
45 changes: 39 additions & 6 deletions R/bootstrap.R
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ NULL
#' Bootstrap 3.
#' @param theme Alternative Bootstrap stylesheet (normally a css file within the
#' www directory, e.g. `www/bootstrap.css`)
#' @param lang ISO 639-1 language code used within the shiny app. Default is set to empty value.
#'
#' @return A UI defintion that can be passed to the [shinyUI] function.
#'
Expand All @@ -26,13 +27,13 @@ NULL
#'
#' @seealso [fluidPage()], [fixedPage()]
#' @export
bootstrapPage <- function(..., title = NULL, responsive = NULL, theme = NULL) {
bootstrapPage <- function(..., title = NULL, responsive = NULL, theme = NULL, lang = NULL) {

if (!is.null(responsive)) {
shinyDeprecated("The 'responsive' argument is no longer used with Bootstrap 3.")
}

attachDependencies(
ui <- attachDependencies(
tagList(
if (!is.null(title)) tags$head(tags$title(title)),
if (!is.null(theme)) {
Expand All @@ -44,6 +45,19 @@ bootstrapPage <- function(..., title = NULL, responsive = NULL, theme = NULL) {
),
bootstrapLib()
)

# Also store `lang` to be passed for rendering processor.
if (!is.null(lang)) {
schloerke marked this conversation as resolved.
Show resolved Hide resolved
if (is.character(lang) && length(lang) == 1) {
# Append lang attribute to be passed to renderPage function
attributes(ui) <- c(attributes(ui), list(lang = lang))
jooyoungseo marked this conversation as resolved.
Show resolved Hide resolved
} else {
warning("Invalid lang value: defaulting to empty string.")
attributes(ui) <- c(attributes(ui), list(lang = NULL))
jooyoungseo marked this conversation as resolved.
Show resolved Hide resolved
}
}

return(ui)
}

#' Bootstrap libraries
Expand Down Expand Up @@ -132,6 +146,7 @@ basicPage <- function(...) {
#' shown in the document).
#' @param bootstrap If `TRUE`, load the Bootstrap CSS library.
#' @param theme URL to alternative Bootstrap stylesheet.
#' @param lang ISO 639-1 language code used within the shiny app. Default is set to empty value.
#'
#' @family layout functions
#'
Expand Down Expand Up @@ -159,22 +174,37 @@ basicPage <- function(...) {
#' )
#' @export
fillPage <- function(..., padding = 0, title = NULL, bootstrap = TRUE,
theme = NULL) {
theme = NULL, lang = NULL) {

fillCSS <- tags$head(tags$style(type = "text/css",
"html, body { width: 100%; height: 100%; overflow: hidden; }",
sprintf("body { padding: %s; margin: 0; }", collapseSizes(padding))
))

if (isTRUE(bootstrap)) {
bootstrapPage(title = title, theme = theme, fillCSS, ...)
ui <- if (isTRUE(bootstrap)) {
jooyoungseo marked this conversation as resolved.
Show resolved Hide resolved
bootstrapPage(title = title, theme = theme, fillCSS, lang = lang, ...)
} else {
tagList(
fillCSS,
if (!is.null(title)) tags$head(tags$title(title)),
...
)
}

# Also store `lang` to be passed for rendering processor.
if (!isTRUE(bootstrap)) {
if (!is.null(lang)) {
if (is.character(lang) && length(lang) == 1) {
# Append lang attribute to be passed to renderPage function
attributes(ui) <- c(attributes(ui), list(lang = lang))
} else {
warning("Invalid lang value: defaulting to empty string.")
attributes(ui) <- c(attributes(ui), list(lang = NULL))
}
}
}

return(ui)
}

collapseSizes <- function(padding) {
Expand Down Expand Up @@ -226,6 +256,7 @@ collapseSizes <- function(padding) {
#' `www/bootstrap.css` you would use `theme = "bootstrap.css"`.
#' @param windowTitle The title that should be displayed by the browser window.
#' Useful if `title` is not a string.
#' @param lang ISO 639-1 language code used within the shiny app. Default is set to empty value.
#' @param icon Optional icon to appear on a `navbarMenu` tab.
#'
#' @return A UI defintion that can be passed to the [shinyUI] function.
Expand Down Expand Up @@ -270,7 +301,8 @@ navbarPage <- function(title,
fluid = TRUE,
responsive = NULL,
theme = NULL,
windowTitle = title) {
windowTitle = title,
lang = NULL) {

if (!missing(collapsable)) {
shinyDeprecated("`collapsable` is deprecated; use `collapsible` instead.")
Expand Down Expand Up @@ -341,6 +373,7 @@ navbarPage <- function(title,
title = windowTitle,
responsive = responsive,
theme = theme,
lang = lang,
tags$nav(class=navbarClass, role="navigation", containerDiv),
contentDiv
)
Expand Down
8 changes: 8 additions & 0 deletions R/shinyui.R
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ withMathJax <- function(...) {
}

renderPage <- function(ui, showcase=0, testMode=FALSE) {
# Check if ui has lang attribute; otherwise, NULL
lang <- if ("lang" %in% names(attributes(ui))) {
jooyoungseo marked this conversation as resolved.
Show resolved Hide resolved
attributes(ui)$lang
jooyoungseo marked this conversation as resolved.
Show resolved Hide resolved
} else {
NULL
}

# If the ui is a NOT complete document (created by htmlTemplate()), then do some
# preprocessing and make sure it's a complete document.
if (!inherits(ui, "html_document")) {
Expand All @@ -38,6 +45,7 @@ renderPage <- function(ui, showcase=0, testMode=FALSE) {
# Put the body into the default template
ui <- htmlTemplate(
system.file("template", "default.html", package = "shiny"),
lang = lang,
body = ui
)
}
Expand Down
2 changes: 1 addition & 1 deletion inst/template/default.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html lang = "{{ lang }}">
schloerke marked this conversation as resolved.
Show resolved Hide resolved
<head>
{{ headContent() }}
</head>
Expand Down
2 changes: 1 addition & 1 deletion inst/template/error.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<html>

<head>
<head lang = "en">
<title>An error has occurred</title>
</head>

Expand Down
4 changes: 3 additions & 1 deletion man/bootstrapPage.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion man/fillPage.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion man/fixedPage.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion man/fluidPage.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion man/navbarPage.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.