Another take on building a multi-lingual shiny app

I was reading this interesting post about how to build a multi-lingual Shiny app. I’m also building a multi-lingual Shiny app and came up with slightly different take on it.

First, I don’t use a function for finding the translation, but a 2D list. This way I can directly get to the translation with a simple access to the list.

Select All Code:
1
2
3
4
5
6
7
translation <- list(
  "youhaveselected" = list("en" = "You have selected:", "fr"="Vous avez sélectionné:"),
  "greetings" = list("en" = "Hello", "fr"="Bonjour")
  )
# then:
translation[['greetings']][['en']] # Hello
translation[['greetings']][['fr']]  # Bonjour

Second, I don’t use observe, as I didn’t find it necessary. I simply have a radio button for switching between languages, and a function tr() to translate a phrase or a list of phrases. Like in the original post, the UI is built from server.R using renderUI().

Select All Code:
1
2
3
  tr <- function(text){ # translates text into current language
    sapply(text,function(s) translation[[s]][[input$language]], USE.NAMES=FALSE)
  }
Select All Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
  # UI
  output$uiObs <- renderUI({
    sliderInput("obs", tr("numberOfObservations"),  
                  min = 1, max = 100, value = 50)
  })
 
  output$uiWeekdays <- renderUI({
    # Using a named list in order to pass the same value regardless of the label (which changes with the language)
    daysValue <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    days <- structure(daysValue, .Names = tr(daysValue))
 
    selectInput(inputId   = "weekdays",
                label     = tr("Selection:"),
                choices   = days,
                multiple  = TRUE)
  })

To make things easier for the translators, the dictionary is stored as a csv file, which is easy to edit. A small R script turns the csv into the expected 2D list, and saves it in a binary file, to avoid re-processing the file every time the user decides to switch language.

Select All Code:
1
2
3
4
5
6
7
8
9
# update the processed translation file translation.bin
# run this every time dictionary.csv is updated 
# it reads the look-up table in dictionary.csv and turns it into a 2D list
 
library(plyr)
translationContent <- read.delim("dictionary.csv", header = TRUE, sep = "\t", as.is = TRUE) 
translation <- dlply(translationContent ,.(key), function(s) key = as.list(s))
 
save(translation, file = "translation.bin")

You can consult the whole code on the github repository and run it directly from R using:

Select All Code:
1
shiny::runGitHub("multilingualShinyApp","chrislad")
This entry was posted in Uncategorized and tagged , , . Bookmark the permalink.

2 Responses to Another take on building a multi-lingual shiny app

  1. Huidong says:

    Hi, you are right, it’s not necessary to use ‘Observe’. I included it because there are other codes (hidden) need it. Anyway, I think your blog is valuable!

    • CL says:

      I see! Indeed, I was a bit confused by the use of observe(), thank you for the clarification!

      Cheers!