Ich schreibe einen benutzerdefinierten Spring Boot-Starter, den andere Entwickler in ihre Anwendungen einfügen, und dieser Starter enthält sofort einsatzbereite Controller und UI-Bildschirme.
Diese UI-Bildschirme sind internationalisiert und die i18n-Schlüssel / Werte befinden sich in einer Paketdatei: com/foo/wherever/i18n.properties
.
Ich möchte sicherstellen, dass diese i18n.properties, wenn mein Starter beim Start geladen wird, automatisch in der MessageSource
der Anwendung verfügbar sind, damit meine Benutzeroberflächen funktionieren (gerendert über normale Spring Controller + ViewResolver + View-Implementierungen) ohne dass der App-Entwickler diese Datei selbst angeben muss .
Mit anderen Worten, sie sollten in der Lage sein, ihren Starter zu ihrem Laufzeitklassenpfad hinzuzufügen, und alles "funktioniert einfach", ohne dass irgendetwas konfiguriert werden muss.
Jetzt habe ich entdeckt, dass der App-Entwickler seine eigene src/main/resources/messages.properties
-Datei erstellen kann und manuell die zusätzliche Nachrichtendatei in application.properties
konfigurieren kann:
Und das wird funktionieren.
Dies erfordert jedoch beides:
spring.messages.basename
manuell konfigurieren - sie ist nicht automatisch. und messages.properties
-Datei in ihrem Klassenpfad haben. Wenn eine messages.properties
-Datei nicht existiert, funktioniert spring.messages.basename
nicht einmal. Selbst wenn sie sich nicht um i18n kümmern, ist dies immer noch erforderlich - nicht wünschenswert. Ich nehme an, könnte meine i18n.properties-Datei in eine Classpath: /messages.properties-Datei in der Start-JAR-Datei verschieben, aber das scheint keine gute Lösung zu sein: Wenn die App-Dev hat ihre eigene messages.properties-Datei nur einer von ihnen würde gelesen werden, was zu fehlenden Nachrichtenwerten führen würde.
Es scheint, als ob Spring Boot MessageSourceAutoConfiguration sollte ein Konzept von CompositeMessageSource
haben, das über eine oder mehrere MessageSource
Instanzen, die verfügbar sind (und Order
ed) im Spring ApplicationContext und Das wird vom DispatcherServlet verwendet. Dies würde es jedem Starter ermöglichen, zu den verfügbaren Nachrichten beizutragen, indem einfach eine MessageSource
in ihrer automatischen Konfiguration deklariert wird
Ist es möglich zu tun, was ich frage? Was ist die beste Lösung für den App-Entwickler?
Vielleicht ist es lang, aber Sie können versuchen, BeanFactoryPostProcessor .
Idee folgt:
Entfernen Sie "messageSource" aus dem Anwendungskontext. Beachten Sie, dass es sich möglicherweise, aber nicht um ein Springboot handeln muss, wenn z. Entwickler möchte eine eigene Implementierung verwenden und keine automatische Autofokus-Boot-Konfiguration verwenden.
Ersetzen Sie es durch Ihre eigene Implementierung, die versucht, "Ihre Schlüssel" und den Restdelegaten auf die ursprüngliche Nachrichtenquelle aufzulösen. Oder umgekehrt, wenn Sie Ihre Übersetzungen durch Entwickler überschreiben wollen (es kann Probleme geben, wenn die ursprüngliche Nachrichtenquelle keine Ausnahme für unbekannte Schlüssel auslöst).
Aber es könnte einen besseren Weg geben, das zu tun.
Ich stelle das auf folgende Weise auf. Ich unterstütze momentan nur en_US, aber es ist eingerichtet, eine beliebige Anzahl von Sprachen mit Internationalisierung (i18n) zu handhaben.
Sehen Sie sich den Code hier an: Code auf github gist
Fügen Sie diese Beans zu Ihrer Application.java hinzu, um Ihr Standardgebietsschema festzulegen und den Standort Ihrer Nachrichtenrequisiten zu konfigurieren.
Der Dienst erhält das Standardgebietsschema aus der Sitzung und erhält dann den Nachrichtentext von den Requisiten
Injizieren Sie die Nachricht svc und geben Sie dann die ID ein, um den Wert aus der Datei reps
zu erhalten
Gehe zu / Ressourcen:
Sie können einen ausführlicheren Artikel zu diesem Thema hier anzeigen: Spring Boot Internationalisierung i18n mit Nachrichteneigenschaften
Sehen Sie sich den Code hier an: Code auf github gist
Mir ist klar, dass dies eine alte und beantwortete Frage ist, aber ich stieß neulich auf das gleiche Problem und schrieb einen Blogbeitrag darüber, wie ich mich entschieden habe, es zu lösen. Ich dachte, ich sollte es hier teilen, da ich von diesem Thread eine Inspiration für meine Lösung bekommen habe.
Kurz gesagt, es braucht sodiks Idee, die Erstellung der MessageSource
-Bohne abzufangen, aber anstatt eine BeanFactoryPostProcessor
zu verwenden, benutze ich eine BeanPostProcessor
, anstatt die ursprüngliche MessageSource
in der Anwendung zu ersetzen Kontext, ich füge nur mein eigenes als Elternteil hinzu:
Sie können den vollständigen Blogpost lesen, in dem ich einige Vorbehalte zu meiner Lösung erläutere: Ссылка
Nach einigem Basteln wurde mir klar, dass die Verwendung von BeanFactoryPostProcessor
falsch war, da dies dazu führen würde, dass die ursprüngliche MessageSource
-Bohne zu früh erstellt würde und die Anwendungseigenschaften ignorierte (was am wichtigsten ist, spring.messages.basename
). Das bedeutet, dass die Anwendung diese Eigenschaften nicht konfigurieren kann. Siehe den Auszug aus dem BeanFactoryPostProcessor Dokumentation unten.
Ein BeanFactoryPostProcessor kann mit Bean-Definitionen interagieren, aber niemals Bean-Instanzen. Dies kann zu vorzeitigen Bean-Instanziierungen führen, die den Container verletzen und unbeabsichtigte Nebenwirkungen verursachen. Wenn eine Bean-Instanz-Interaktion erforderlich ist, sollten Sie stattdessen BeanPostProcessor implementieren.
Ich habe das obige Beispiel aktualisiert, um stattdessen BeanPostProcessor
zu verwenden, wodurch die Bean-Instanz und nicht die Bean-Definition geändert wird.
Tags und Links java spring spring-boot internationalization