Appsilon/shiny.i18n

[Bug]: Problem in the uiOutput and renderUI in modules

Closed this issue · 9 comments

Guidelines

  • I agree to follow this project's Contributing Guidelines.

Project Version

0.2.1

Platform and OS Version

Windows 10 x64

Existing Issues

#48 #62

What happened?

Dear creators,
first of all thank you for developing this package which I have started to use and appreciate its potentialities.

The package works properly for every section except when we pass inside a module and inside uiOutput and renderUI function.

In fact when I go to edit the languages it translates everything except the part that are inside those two functions.

Below you will find code to reproduce the problem, but if you need more information I am available.

Could you help me to solve this?

Steps to reproduce

app_ui.R

#' The application User-Interface
#'
#' @param request Internal parameter for `{shiny}`.
#'     DO NOT REMOVE.
#' @import shiny
#' @noRd

i18n <- shiny.i18n::Translator$new(translation_json_path='translations/translation.json')
i18n$set_translation_language('Italiano')

app_ui <- function(request) {
  tagList(
    # Leave this function for adding external resources
    golem_add_external_resources(),
    # Your application UI logic
    fluidPage(

      h1(i18n$t("Titolo")),

      selectInput(inputId='selected_language',
                  label=i18n$t('Lingua'),
                  multiple = FALSE,
                  choices = i18n$get_languages(),
                  selected = i18n$get_key_translation()),

      mod_name_of_module1_ui("name_of_module1_1"),

      hr(),
      hr(),

      mod_name_of_module2_ui("name_of_module2_1")

    )
  )
}

#' Add external Resources to the Application
#'
#' This function is internally used to add external
#' resources inside the Shiny application.
#'
#' @import shiny
#' @importFrom golem add_resource_path activate_js favicon bundle_resources
#' @noRd
golem_add_external_resources <- function() {
  add_resource_path(
    "www",
    app_sys("app/www")
  )

  tags$head(
    favicon(),
    bundle_resources(
      path = app_sys("app/www"),
      app_title = "translationtest"
    ),
    shiny.i18n::usei18n(i18n)
    # Add here other external resources
    # for example, you can add shinyalert::useShinyalert()
  )
}

app_server.R

#' The application server-side
#'
#' @param input,output,session Internal parameters for {shiny}.
#'     DO NOT REMOVE.
#' @import shiny
#' @noRd
app_server <- function(input, output, session) {
  # Your application server logic

  library(shiny)
  library(shiny.i18n)

  i18n <- shiny.i18n::Translator$new(translation_json_path='translations/translation.json')
  i18n$set_translation_language('Italiano')

  observeEvent(input$selected_language, {
    update_lang(session, input$selected_language)
  })

  mod_name_of_module1_server("name_of_module1_1")

  mod_name_of_module2_server("name_of_module2_1")

}

mod_name_of_module1.R

#' name_of_module1 UI Function
#'
#' @description A shiny Module.
#'
#' @param id,input,output,session Internal parameters for {shiny}.
#'
#' @noRd
#'
#' @importFrom shiny NS tagList
mod_name_of_module1_ui <- function(id){
  ns <- NS(id)
  tagList(

    h4("We are in the module 1"),
    h4(i18n$t("Titolo")),

    uiOutput(ns("module_1_ui")),
    uiOutput(ns("module_2_ui"))

  )
}

#' name_of_module1 Server Functions
#'
#' @noRd
mod_name_of_module1_server <- function(id){
  moduleServer( id, function(input, output, session){
    ns <- session$ns

    output$module_1_ui<-renderUI({
      h4("We are in the module 1 - renderui section")
    })

    output$module_2_ui<-renderUI({
      h4(i18n$t("Titolo"))
    })

  })
}

## To be copied in the UI
# mod_name_of_module1_ui("name_of_module1_1")

## To be copied in the server
# mod_name_of_module1_server("name_of_module1_1")

mod_name_of_module2.R

#' name_of_module2 UI Function
#'
#' @description A shiny Module.
#'
#' @param id,input,output,session Internal parameters for {shiny}.
#'
#' @noRd
#'
#' @importFrom shiny NS tagList
mod_name_of_module2_ui <- function(id){
  ns <- NS(id)
  tagList(

    h4("We are in the module 2"),
    h4(i18n$t("Titolo")),

    uiOutput(ns("module_1_ui")),
    uiOutput(ns("module_2_ui"))

  )
}

#' name_of_module2 Server Functions
#'
#' @noRd
mod_name_of_module2_server <- function(id){
  moduleServer( id, function(input, output, session){
    ns <- session$ns

    output$module_1_ui<-renderUI({
      h4("We are in the module 2 - renderui section")
    })

    output$module_2_ui<-renderUI({
      h4(i18n$t("Titolo"))
    })

  })
}

## To be copied in the UI
# mod_name_of_module2_ui("name_of_module2_1")

## To be copied in the server
# mod_name_of_module2_server("name_of_module2_1")

translation.json

{
    "languages": ["Italiano","English","Brasileiro","Español","Français","Deutsch","**", "やまと"],
    "translation": [
        {
            "Italiano": "Titolo",
            "English": "Title",
            "Brasileiro": "Título",
            "Español": "Título",
            "Français": "Titre",
            "Deutsch" : "Titel",
            "**": "标题",
            "やまと": "タイトル"
        }
    ]
}

Expected behavior

When I change the selectinput I expect everything to be translated instead the elements within the forms in the uiouput and renderui section do not change

Any news or update about this issue?

@agronomofiorentini, did you find a solution to this?
I have the same issue and not sure if it's a bug or something wrong on my end.

I'm sorry but I haven't found any solution for this yet.
In fact I was looking for help from the appsilon team to figure out.

Here is my reproducible example of the problem, based on the solution posted here:

library(shiny)
library(shiny.i18n)

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

i18n$set_translation_language("pl")

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 = "Polish")
          update_lang(global_session, "en")
        } else {
          updateActionButton(session, "go",
                             label = "English")
          update_lang(global_session, "pl")
        }
      })
    }
  )
}

another_UI <- function(id, i18n) {
  ns <- NS(id)
  uiOutput(ns("test"))
}

another_Server <- function(id, global_session) {
  moduleServer(
    id,
    function(input, output, session) {

      ns <- NS(id)
      output$test <- renderUI(tagList(
        usei18n(i18n),
        p(i18n$t("Hello Shiny!"))
      ))

    }
  )
}

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

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

shinyApp(ui, server)

Dear @AdrianHordyk

I have seen the #48

I tried to implement the suggested code, but i have still problem in the renderui section.

The follow is the code

library(shiny)
library(shiny.i18n)

mod_name_of_module1_ui <- function(id, i18n){

  ns <- NS(id)

  tagList(
    h4("We are in the module 1"),
    h4(i18n$t("Titolo")),

    uiOutput(ns("module_1_ui")),
    uiOutput(ns("module_2_ui")))

}

mod_name_of_module1_server <- function(id, global_session){
  moduleServer(id, function(input, output, session){

    ns <- session$ns

    output$module_1_ui<-renderUI({
      h4("We are in the module 1 - renderui section")
    })

    output$module_2_ui<-renderUI(
      tagList(
        shiny.i18n::usei18n(i18n),
        h4(i18n$t("Titolo"))
      )
    )

  })
}

mod_name_of_module2_ui <- function(id, i18n){
  ns <- NS(id)
  tagList(

    h4("We are in the module 2"),
    h4(i18n$t("Titolo")),

    uiOutput(ns("module_1_ui")),
    uiOutput(ns("module_2_ui"))

  )
}

mod_name_of_module2_server <- function(id, global_session){
  moduleServer( id, function(input, output, session){
    ns <- session$ns

    output$module_1_ui<-renderUI({
      h4("We are in the module 2 - renderui section")
    })

    output$module_2_ui<-renderUI(
      tagList(
        shiny.i18n::usei18n(i18n),
        h4(i18n$t("Titolo")))
    )

  })
}

i18n <- shiny.i18n::Translator$new(translation_json_path='translations/translation.json')
i18n$set_translation_language('Italiano')

app_ui <- function(request) {
  tagList(
    # Your application UI logic
    fluidPage(
      shiny.i18n::usei18n(i18n),
      h1(i18n$t("Titolo")),

      selectInput(inputId='selected_language',
                  label=i18n$t('Lingua'),
                  multiple = FALSE,
                  choices = i18n$get_languages(),
                  selected = i18n$get_key_translation()),

      mod_name_of_module1_ui("name_of_module1_1", i18n = i18n),

      hr(),
      hr(),

      mod_name_of_module2_ui("name_of_module2_1", i18n = i18n)

    )
  )
}

app_server <- function(input, output, session) {
  # Your application server logic

  library(shiny)
  library(shiny.i18n)

  observeEvent(input$selected_language, {
    update_lang(session, input$selected_language)
  })

  mod_name_of_module1_server("name_of_module1_1", global_session = session)

  mod_name_of_module2_server("name_of_module2_1", global_session = session)

}

shinyApp(app_ui, app_server)

The traslation.json is the follow

{
    "languages": ["Italiano","English","Brasileiro","Español","Français","Deutsch","**", "やまと"],
    "translation": [
        {
            "Italiano": "Titolo",
            "English": "Title",
            "Brasileiro": "Título",
            "Español": "Título",
            "Français": "Titre",
            "Deutsch" : "Titel",
            "**": "标题",
            "やまと": "タイトル"
        }
    ]
}

@agronomofiorentini I am having the same problem.

At first I thought #48 solved it but it doesn't.
I posted my code as a minimum reproducible example of the problem based on #48.

Ok, setting i18n as a reactive object seems to do the trick:

library(shiny)
library(shiny.i18n)

translator  <- Translator$new(translation_json_path = "../data/translation.json")
translator$set_translation_language('en')

another_UI <- function(id) {
  ns <- NS(id)
  uiOutput(ns("test"))
}

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

      ns <- NS(id)
      output$test <- renderUI(tagList(
        usei18n(i18n()),
        h1('renderUI in module'),
        p(i18n()$t("Hello Shiny!"))
      ))

    }
  )
}

server <- function(input, output, session) {

  i18n <- reactive({
    req(input$selected_language)
    selected <- input$selected_language
    if (length(selected) > 0 && selected %in% translator$get_languages()) {
      translator$set_translation_language(selected)
    }
    translator
  })

  output$ui <- renderUI({
    tagList(
      selectInput('selected_language',
                  "Select language",
                  choices = translator$get_languages(),
                  selected = translator$get_key_translation()
      )


    )
  })

  output$text <- renderUI({
    tagList(
      h1('renderUI in server'),
      h2(i18n()$t("Hello Shiny!"))
    )

  })

  lang <- reactive({
    req(input$selected_language)
    input$selected_language
  })

  observeEvent(lang(), {
    shiny.i18n::update_lang(session, input$selected_language)
    print(i18n()$t('Hello Shiny!'))

  }, ignoreInit = FALSE)

  another_Server("test", i18n=i18n)
}

ui <- fluidPage(
  uiOutput("ui"),
  uiOutput("text"),
  another_UI("test")
)

shinyApp(ui, server)

Now to see if I can replicate this in my more complex use case

I will try your suggestion and i will tell you if is working also from my side.

Thanks @AdrianHordyk

Hey @AdrianHordyk

It's working.

This is my code

library(shiny)
library(shiny.i18n)

translator <- shiny.i18n::Translator$new(translation_json_path='translation.json')
translator$set_translation_language('Italiano')

mod_name_of_module1_ui <- function(id){
  
  ns <- NS(id)
  
  tagList(
    h4("We are in the module 1"),
    h4(translator$t("Titolo")),
    
    uiOutput(ns("module_1_ui")),
    uiOutput(ns("module_2_ui")))
  
}

mod_name_of_module1_server <- function(id, i18n){
  moduleServer(id, function(input, output, session){
    
    ns <- session$ns
    
    output$module_1_ui<-renderUI({
      h4("We are in the module 1 - renderui section")
    })
    
    output$module_2_ui<-renderUI(
      tagList(
        shiny.i18n::usei18n(i18n()),
        h4(i18n()$t("Titolo"))
      )
    )
    
  })
}

mod_name_of_module2_ui <- function(id){
  ns <- NS(id)
  tagList(

    h4("We are in the module 2"),
    h4(translator$t("Titolo")),

    uiOutput(ns("module_1_ui")),
    uiOutput(ns("module_2_ui"))

  )
}

mod_name_of_module2_server <- function(id, i18n){
  moduleServer( id, function(input, output, session){
    ns <- session$ns

    output$module_1_ui<-renderUI({
      h4("We are in the module 2 - renderui section")
    })

    output$module_2_ui<-renderUI(
      tagList(
        shiny.i18n::usei18n(i18n()),
        h4(i18n()$t("Titolo")))
    )

  })
}

app_ui <- function(request) {
  tagList(
    fluidPage(
      shiny.i18n::usei18n(translator),
      h1(translator$t("Titolo")),
      
      selectInput(inputId='selected_language',
                  label=translator$t('Lingua'),
                  multiple = FALSE,
                  choices = translator$get_languages(),
                  selected = translator$get_key_translation()),
      
      mod_name_of_module1_ui("name_of_module1_1"),
      
      hr(),
      hr(),
      
      mod_name_of_module2_ui("name_of_module2_1")
      
    )
  )
}

app_server <- function(input, output, session) {
  
  observeEvent(input$selected_language, {
    update_lang(session, input$selected_language)
  })
  
  i18n <- reactive({
    req(input$selected_language)
    selected <- input$selected_language
    if (length(selected) > 0 && selected %in% translator$get_languages()) {
      translator$set_translation_language(selected)
    }
    translator
  })
  
  mod_name_of_module1_server("name_of_module1_1", i18n = i18n)
  
  mod_name_of_module2_server("name_of_module2_1", i18n = i18n)
  
}

shinyApp(app_ui, app_server)

Thanks again