Click on flag icon to switch the language

Hi all,
I’m using Plotly Dash to create an app. In this app I would like to change some words from language DE to EN.
I would like to use a flag for selecting the language. Is it possible?

regards
Torsten

Hey @Torsten, yes thats possible.

Usually you store the words to translate in a json file in the assets folder. See also:

1 Like

Another option for creating a multi-language app is to make a container and put the content of your app in this container. For generating the content of the container you do something like

def render_app_content(language: str = "en") -> html.Div:
    return html.Div([.. app content here ...])

The language selection is done in a dropdown, and you create a callback that rerenders the app content whenever the language selection changes.

For the translation part, you can use the i18n library.
Whenever you have text that you want to be translated you use something like

i18n.t("general.input_table_title", locale=language)

You create the different translations in a path, locale for example. If you use yaml format, you name the files <namespace>.<lang_code>.yml, so for the above example to work, you have general.en.yml and general.de.yml in the locale directory.

The content of the yml file looks like

---
<lang_code>:
  <var_name>: <text content>

so for the example above you have

# general.en.yml
---
en:
  input_table_title: Important table
# general.de.yml
---
de:
  input_table_title: Wichtiger Tisch

You set up i18n with

i18n.set('load_path', [<path_to_locale_directory>])

Bonus:
You can use Dash iconify for the country flags

flag_icons_tag = "flag:<code>-4x3"
country_codes = {"gb": "en", "de": "de"}
language_dropdown_config = {
        'default': "en",
        'options': [
                {
                    "label": DashIconify(
                        icon=flag_icons_tag.replace("<code>", country_code)
                    ),
                    "value": language_code,
                }
                for country_code, language_code in country_codes.items()
            ]
}
1 Like

Hi Tobs,

Thank you for this response. I will try this in the next 5 days. I will keep you informed here.

Best regards
Torsten

Hello Tobs,
sorry,I haven’t quite understood it yet. Could you perhaps create a small example for me?

This here is what I have yet. Only a small app.

import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
from datetime import datetime, timedelta
import dash_bootstrap_components as dbc  # pip install dash-bootstrap-components
from dash_iconify import DashIconify

from flask import Flask
from waitress import serve

server = Flask(__name__)



app = dash.Dash(__name__,
                meta_tags=[{"name": "viewport", "content": "width=device-width, initial-scale=1"}],
                server=server)#,external_stylesheets=[dbc.themes.SLATE])

server = app.server

app.layout = html.Div([
    dbc.Row([
            dcc.Dropdown(['DE', 'EN', 'IT'], 'DE', id='language-dropdown'),
        ]),
    dbc.Row([
        html.Div([
            html.H4(id='textarea-example', style={'color': 'blue'})
            ])
        ]),
])


   
@app.callback(
    Output('textarea-example', 'children'),
    Input('language-dropdown', 'value'))
def update_app(lang):
    val = f"es wurde {lang} gewählt"

    return val


if __name__ == '__main__':
    app.run_server(debug=False, port=5555)  

Thanks
Torsten

Hi @Torsten,

Below I added a minimal app and three yml files. Create a locale directory next to your app.py and put the three yml files in there:

- project_dir
  |- locale
  |  |- general.de.yml
  |  |- general.en.yml
  |  |- general.it.yml
  |- app.py

I added three example texts in there, one static text sample, one text sample with a variable in it and one text sample that is updated via a callback. So you get an idea of what is possible.

Note: Looking at your example, you are using the old way of importing things from Dash. Look at the included example to see what the latest import system looks like.

Note 2: You are explicitly creating a server, unless you need to do things with the Flask server, you can ignore that.

Since we are working with yml files, make sure to install i18n like:

pip install python-i18n[YAML]
# app.py
from pathlib import Path

import dash
from dash import Input, Output, State, dcc, html, callback
import dash_bootstrap_components as dbc
from dash_iconify import DashIconify
import i18n


app = dash.Dash(
    __name__,
)

i18n.set("load_path", [str(Path(__file__).parent / "locale")])

flag_icons_tag = "flag:<code>-4x3"
country_codes = {"gb": "en", "de": "de", "it": "it"}
language_dropdown_config = {
    "default": "en",
    "options": [
        {
            "label": DashIconify(icon=flag_icons_tag.replace("<code>", country_code)),
            "value": language_code,
        }
        for country_code, language_code in country_codes.items()
    ],
}


def render_app_content(language: str = "en") -> dbc.Row:
    return dbc.Row(
        [
            dbc.Col(
                [
                    html.H4(
                        id="textarea-example",
                        children=[i18n.t("general.welcome_message", locale=language)],
                        style={"color": "blue"},
                    ),
                    html.Div(
                        id="dynamic_text",
                        children=[
                            i18n.t(
                                "general.dynamic_text", locale=language, lang=language
                            )
                        ],
                    ),
                    dbc.Button(
                        id="button",
                        children="Count clicks",
                    ),
                    html.Div(
                        id="callback_update",
                        children=[],
                    ),
                ]
            )
        ]
    )


app.layout = dbc.Container(
    [
        dbc.Row(
            [
                dcc.Dropdown(
                    options=language_dropdown_config["options"],
                    value=language_dropdown_config["default"],
                    id="language-dropdown",
                    style={"width": "60px"},
                    clearable=False,
                ),
            ]
        ),
        dbc.Container(
            id="app_container",
            children=[render_app_content(language=language_dropdown_config["default"])],
        ),
    ],
)


@callback(
    Output("app_container", "children"),
    Input("language-dropdown", "value"),
)
def update_app(selected_language: str) -> dbc.Row:
    return render_app_content(language=selected_language)


@callback(
    Output("callback_update", "children"),
    Input("button", "n_clicks"),
    State("language-dropdown", "value"),
)
def count_clicks(n_clicks: int, language: str) -> str:
    if not language:
        language = language_dropdown_config["default"]
    return i18n.t("general.callback_update", locale=language, count=n_clicks)


if __name__ == "__main__":
    app.run_server(debug=True)
# general.en.yml
en:
  welcome_message: Welcome to our site!
  dynamic_text: "You have selected %{lang}"
  callback_update: You have clicked the button %{count} times
# general.de.yml
de:
  welcome_message: Willkommen auf unserer Seite!
  dynamic_text: "Es wurde %{lang} gewählt"
  callback_update: Sie haben den Button %{count} Mal geklickt
# general.it.yml
it:
  welcome_message: Benvenuti sul nostro sito!
  dynamic_text: "Hai selezionato %{lang}"
  callback_update: Hai cliccato il pulsante %{count} volte
2 Likes

Hi Tobs,

Thanks a lot for this demo app. Now I know how it works.

BR
Torsten