Search code examples
internationalizationshiny-reactivity

Reactivity conundrum in shiny; dynamically translating text going into selectInput()


I am working on a multilingual shiny app using the shiny.i18n package to translate different parts of the UI. It works really well until I tried to dynamically translate the text inside a specific selectInput menu. Some reproducible code below:

# Translating text of a menu item from data

library(shiny)
library(shiny.i18n)
library(tidyverse)

# Create translation file and save in a directory called trans
system("mkdir trans")
translation_key <- data.frame(es = c("Cambiar de lenguaje", "Seleccione un proyecto", "Todos"),
                              en = c("Change language", "Select a project", "All")
                              )
write.csv(translation_key, "trans/translation_key.csv",
          row.names = FALSE, 
          quote = FALSE)

# Create data object
data <- data.frame(project_name =c("Todos","proj1", "proj2"),
                   n = c(20,30,40)
                   )
# Setup translator
trans <- Translator$new(translation_csvs_path = "trans")
trans$set_translation_language("es")


# Define UI 
ui <- fluidPage(
  usei18n(trans),
  

    # Application title
    titlePanel("Reactivity test"),
        
        mainPanel(
          selectInput('selected_language',
                      trans$t("Cambiar de lenguaje"),
                      choices = trans$get_languages()
                    ),
          selectInput("project_name",
                      trans$t("Seleccione un proyecto"),
                      choices = NULL
          ),
          textOutput("n")
          )
)



# server part
server <- function(session, input, output) {
  
  
# update languae  
   observeEvent(input$selected_language, {
     
     update_lang(session, input$selected_language)
     print(paste("Language change!", input$selected_language))
   })
  
# change the first element of data$project and translate it! It does not do it! 
  data_rv <- eventReactive(input$selected_language, {
    
    data$project_name[1] <- trans$t("Todos")
    data
    
    
  })
  
  # update the selection for project name depending on the language
  observeEvent(data_rv(), {
    updateSelectInput(session, inputId = "project_name", 
                      choices = unique(data_rv()$project_name))
  })
  
  # print the n associated with project_name selected
  output$n <- renderText({
    req(input$project_name)
    res <- data_rv() %>% filter(project_name == input$project_name)
    res$n
  })
}
    
# Run the application 
shinyApp(ui = ui, server = server) 

I attempt the translation of the first element of data$project_name inside an eventReactive call that returns the modified translated object. The problem is that the translation does not happen until after the menu for project_name is rendered (see screenshot below). Reactivity test app

The application starts by default in Spanish (es) and when changed to English (en), everything is translated except the first item in the Select a project menu (it should say All instead of Todos).

I have found a solution using uiOutput and renderUI but the application I am working on has a very complex layout of panels and tabs and I rather not rework all the code if I can help it. Can someone recommend a workaround that works from the browser side. Thanks,


Solution

  • An alternative in this case could be making data_rv a reactive expression with a req() instead of an eventReactive. It may also keep it simple for your purpose.

    I tried it like this with your example:

      # change the first element of data$project and translate it! 
      data_rv <- reactive({
        req(input$selected_language)
        data$project_name[1] <- trans$t(data$project_name[1])
        data
        
      })
    

    Seems it checks out! reactivity question image here

    Note: I translated reactivity test to prueba de reactividad for clarity but is not in the original reproducible example