Appsilon / shiny.i18n

Shiny applications internationalization made easy
https://appsilon.github.io/shiny.i18n/
Other
168 stars 38 forks source link

update_lang won't work inside of a shiny module #48

Closed ttuff closed 2 years ago

ttuff commented 3 years ago

I have tried and tried to work around this problem but I can't seem to get it figured out. The update_lang() function works in a simple app without modules, but if I put it in my large app or just simple modules, the update fails to perform. I've included a reproducible chunk below where the button label will update, but the translation won't fire. Could you have a look and see if you can find any workarounds? Thanks, Ty

library(shiny) library(shiny.i18n)

i18n <- Translator$new(translation_json_path = "translation.json") i18n$set_translation_language("fr")

languageButton_UI <- function(id, i18n) { ns <- NS(id) tagList( usei18n(i18n), actionButton(ns("go"), "English"), h2(i18n$t("Hello Shiny!")) ) }

languageButton_Server <- function(id, i18n) { moduleServer( id, function(input, output, session) {

    ns <- NS(id)
    observeEvent(input$go,{
      print(input$go[1])
      if((input$go[1] %% 2) != 0){
        updateActionButton(session, "go",
                           label = "Français")
        update_lang(session, "en")  # This line is not updating properly in module
      } else {
        updateActionButton(session, "go",
                           label = "English")
        update_lang(session, "fr") # This line is not updating properly in module
        }
    })
  }
)

}

ui <- fluidPage( languageButton_UI("language_button", i18n = i18n) )

server <- function(input, output, session) { languageButton_Server("language_button", i18n = i18n) }

shinyApp(ui, server)

dokato commented 3 years ago

Hey @ttuff , thanks for using shiny.i18n. That was a bit of a riddle, but after some debugging we found that this has to do with how Shiny handles session within the module. Apparently this is done via some session_proxy object that overrides sendInputMessage method for sending the update to JS code (we think that it adds namespace to id, but not sure... 🤔 ).

While we are working on more robust solution #49, see this workaround, where you pass the global session as an argument:

library(shiny)
library(shiny.i18n)

i18n <- Translator$new(translation_json_path = "../data/translation.json")

i18n$set_translation_language("fr")

languageButton_UI <- function(id, i18n) {
  ns <- NS(id)
  tagList( usei18n(i18n), actionButton(ns("go"), "English"), h2(i18n$t("Hello Shiny!"))
  )
}

languageButton_Server <- function(id, global_session) {
  moduleServer(
    id,
    function(input, output, session) {
      ns <- NS(id)
      observeEvent(input$go,{
        print(input$go[1])
        if((input$go[1] %% 2) != 0){
          updateActionButton(session, "go",
                             label = "Français")
          update_lang(global_session, "en")
        } else {
          updateActionButton(session, "go",
                             label = "English")
          update_lang(global_session, "fr")
        }
      })
    }
  )
}

ui <- fluidPage(
  languageButton_UI("language_button", i18n = i18n)
)

server <- function(input, output, session) {
  languageButton_Server("language_button", global_session = session)
}

shinyApp(ui, server)
ttuff commented 3 years ago

Thank you!!