Skip to content

Commit 68251da

Browse files
Merge pull request #51156 from quarkusio/dev-ui-i18n-docs
Document i18n support for Quarkus Dev UI
2 parents 9d794a5 + a06ea5a commit 68251da

File tree

1 file changed

+211
-2
lines changed

1 file changed

+211
-2
lines changed

docs/src/main/asciidoc/dev-ui.adoc

Lines changed: 211 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ image::devui_layout_settings.png[Dev UI Settings]
152152
The settings page is a dialog that contains settings for Dev UI:
153153

154154
- Theme (Change between Desktop/Light/Dark
155+
- Locale (Change to another supported language/locale)
155156
- Bugs / Feature requests
156157
- Storage (Manage local browser storage used in Dev UI)
157158
- Dev MCP (Enable your Dev Mode to expose a MCP Server)
@@ -619,6 +620,214 @@ export class QwcMyExtensionPage extends QwcHotReloadElement {
619620
}
620621
----
621622

623+
===== Add i18n to your pages
624+
625+
Quarkus Dev UI supports full internationalization (i18n).
626+
To enable this in your extension, you must externalize all user-visible text into translation files.
627+
628+
All translation files must be placed under:
629+
630+
`<extension>/deployment/src/main/resources/dev-ui/i18n/`
631+
632+
====== Translation file layout
633+
634+
Each translation file is a plain JavaScript module following one of these naming patterns:
635+
636+
* `languagecode.js`
637+
* `languagecode-COUNTRYCODE.js`
638+
639+
The base *language* file contains translations common to all dialects.
640+
A *country-specific* file contains only the keys that differ from the base.
641+
642+
For example, English:
643+
644+
* `en.js` — base English
645+
* `en-US.js` — American English (only overrides)
646+
* `en-GB.js` — British English (only overrides)
647+
648+
French follows the same pattern:
649+
650+
* `fr.js` — base French
651+
* `fr-FR.js` — France-specific
652+
* `fr-CA.js` — Canada-specific
653+
654+
A list of locale codes can be found here: https://simplelocalize.io/data/locales/
655+
656+
Quarkus Dev UI defaults to English.
657+
If the user’s browser locale is supported, that locale becomes the active default.
658+
Users may also manually change the locale from the Dev UI settings dialog.
659+
660+
====== Translation file format
661+
662+
Each translation file must export a constant named `templates` containing key–value pairs:
663+
664+
[source,javascript]
665+
----
666+
export const templates = {
667+
'myextension-some-key': 'Some translated value'
668+
};
669+
----
670+
671+
All keys must follow this naming convention:
672+
673+
`<extensionArtifactId>-<id>`
674+
675+
where `<extensionArtifactId>` is taken from the `<artifactId>` of your extension’s runtime module.
676+
677+
Example (Agroal):
678+
679+
[source,xml]
680+
----
681+
<artifactId>quarkus-agroal</artifactId>
682+
----
683+
684+
All translation keys must therefore start with:
685+
686+
`quarkus-agroal-`
687+
688+
*Required keys*
689+
690+
1. Metadata
691+
692+
To translate the extension description (taken from the <description> element of your runtime POM), define:
693+
694+
`<extensionArtifactId>-meta-description`
695+
696+
Example:
697+
698+
[source,javascript]
699+
----
700+
'quarkus-agroal-meta-description': 'JDBC Datasources and connection pooling'
701+
----
702+
703+
1. Page titles
704+
705+
Each Dev UI page (created with CardPageBuildItem) needs a translation key for its title.
706+
707+
For a page titled "Database view" in Agroal:
708+
709+
[source,java]
710+
----
711+
cardPageBuildItem.addPage(Page.webComponentPageBuilder()
712+
.icon("font-awesome-solid:database")
713+
.title("Database view")
714+
.componentLink("qwc-agroal-datasource.js"));
715+
----
716+
717+
The translation key becomes `quarkus-agroal-database_view`.
718+
(for the title, spaces replaced with underscores, lower-case.)
719+
720+
Example entry:
721+
722+
[source,javascript]
723+
----
724+
'quarkus-agroal-database_view': 'Database view'
725+
----
726+
727+
1. General text
728+
729+
All other user-visible strings in your JS code should also be externalized.
730+
731+
Example:
732+
733+
[source,javascript]
734+
----
735+
import { str } from '@lit/localize';
736+
737+
export const templates = {
738+
// Metadata
739+
'quarkus-agroal-meta-description': 'JDBC Datasources and connection pooling',
740+
741+
// Pages
742+
'quarkus-agroal-database_view': 'Database view',
743+
744+
// General
745+
'quarkus-agroal-fetching-data-sources': 'Fetching data sources...'
746+
};
747+
----
748+
749+
*Updating your JavaScript pages*
750+
751+
To use translations inside your Lit components, update your code as follows.
752+
753+
1. Import the localization helpers
754+
755+
[source,javascript]
756+
----
757+
import { msg, str, updateWhenLocaleChanges } from 'localization';
758+
----
759+
760+
- msg: lookup a translation key
761+
- str: create dynamic strings with variables
762+
- updateWhenLocaleChanges: tells Lit to re-render automatically when language changes
763+
764+
1. Register for locale changes
765+
766+
Add the following in your constructor:
767+
768+
[source,javascript]
769+
----
770+
constructor() {
771+
super();
772+
updateWhenLocaleChanges(this);
773+
}
774+
----
775+
776+
1. Replace inline text with translation lookups
777+
778+
Before:
779+
780+
[source,javascript]
781+
----
782+
return this._renderProgressBar('Fetching data sources...');
783+
----
784+
785+
After:
786+
787+
[source,javascript]
788+
----
789+
return this._renderProgressBar(
790+
msg('Fetching data sources...', { id: 'quarkus-agroal-fetching-data-sources' })
791+
);
792+
----
793+
794+
If the key does not exist in the current locale, the fallback text ('Fetching data sources...') is used automatically.
795+
796+
Examples:
797+
798+
[source,javascript]
799+
----
800+
// en.js
801+
'quarkus-agroal-fetching-data-sources': 'Fetching data sources...'
802+
803+
// fr.js
804+
'quarkus-agroal-fetching-data-sources': 'Récupération des sources de données…'
805+
----
806+
807+
1.1 Using variables inside translations
808+
809+
For dynamic messages, wrap the default string in str:
810+
811+
[source,javascript]
812+
----
813+
} catch (error) {
814+
notifier.showErrorMessage(
815+
msg(str`Failed to save file: ${error}`, { id: 'quarkus-agroal-file-save-failed' })
816+
);
817+
}
818+
----
819+
820+
In translation files, use positional variables (${0}, ${1}, …):
821+
822+
[source,javascript]
823+
----
824+
// en.js
825+
'quarkus-agroal-file-save-failed': str`Failed to save file: ${0}`,
826+
827+
// fr.js
828+
'quarkus-agroal-file-save-failed': str`Échec de l’enregistrement du fichier : ${0}`,
829+
----
830+
622831
===== UI Components
623832

624833
====== Vaadin Web Components
@@ -770,7 +979,7 @@ this.storageControl.set('height', 123); // Set some val
770979

771980
https://github.com/quarkusio/quarkus/blob/main/extensions/devui/resources/src/main/resources/dev-ui/qwc/qwc-footer.js[Example code]
772981

773-
======= Per Application
982+
*Per Application*
774983

775984
You can narrow the score of the storage further by the current application:
776985

@@ -779,7 +988,7 @@ You can narrow the score of the storage further by the current application:
779988
storageControl = new StorageController(this, true); // Passing in true will scope per application
780989
----
781990

782-
======= Storage Setting
991+
*Storage Setting*
783992

784993
Users can have a raw view on the storage in the settings page:
785994

0 commit comments

Comments
 (0)