Design A Bilingual Shiny Application
It’s a common requirement that your Shiny application should be bilingual. I have tried several methods and finally I got one which is not so difficult to maintain.
My idea is:
- Create a bilingual dictionary or a lookup table which contains three columns: value, English name and Norwegian name, like this one:
- Create a radio input with English and Norsk two options in file ui.R.
radioButtons(inputId = "lang", label = "",
choices = c("English" = "en", "Norsk" = "no"),
selected = "English"),
- Create a function that converts value’s name to Norsk if user choose the Norsk radio.
## Bilingual lookup table;
LANG <- unique(read.csv("www/lang.csv", sep = ";", stringsAsFactors = FALSE))
E2N <- function(en, D = LANG) {
for (i in 1:length(en)) {
id <- which(D$value %in% en[i])
if (length(id) == 0) {
id <- which(D$EN %in% en[i])
if (length(id) == 1) {
en[i] <- ifelse(input$lang == "no", D$NO[id], D$EN[id])
} else if (length(id) > 1) {
print("Mulit-variable matched!")
}
} else if (length(id) == 1) {
en[i] <- ifelse(input$lang == "no", D$NO[id], D$EN[id])
} else if (length(id) > 1) {
print("Mulit-variable matched!")
}
}
return(en)
}
The ui.R file can be written as follow:
shinyUI(pageWithSidebar(
## English or Norwegain?
radioButtons(inputId = "lang", label = "",
choices = c("English" = "en", "Norsk" = "no"),
selected = "English"),
# Select unit;
sidebarPanel(
uiOutput("uiUnit")
),
mainPanel(
h1(textOutput("text1"))
)
))
In server.R file, we need load the E2N function first:
shinyServer(function(input, output, session) {
LANG <- data.frame(value = c("time", "day", "week", "month"),
EN = c("Time", "Day", "Week", "Month"),
NO = c("Tid", "Dag", "Uke", "Maaned"),
stringsAsFactors = FALSE)
observe({
E2N <- function(en, D = LANG) {
for (i in 1:length(en)) {
id <- which(D$value %in% en[i])
if (length(id) == 0) {
id <- which(D$EN %in% en[i])
if (length(id) == 1) {
en[i] <- ifelse(input$lang == "no", D$NO[id], D$EN[id])
} else if (length(id) > 1) {
print("Mulit-variable matched!")
}
} else if (length(id) == 1) {
en[i] <- ifelse(input$lang == "no", D$NO[id], D$EN[id])
} else if (length(id) > 1) {
print("Mulit-variable matched!")
}
}
return(en)
}
## Input;
output$uiUnit <- renderUI({
Items <- c("day", "week", "month")
selectInput(inputId = "unit",
label = E2N("time"),
choices = E2N(Items),
multiple = TRUE)
})
## Output;
output$text1 <- renderText({
E2N(input$unit)
})
})
})
One shortcoming of this method is: when switching language, the application goes back to its original state. You can run above demo in R console:
library(shiny)
runGist("https://gist.github.com/withr/3c01413b70b8a82706ab")
Written on October 17, 2014