Benutzerdefinierter Spring Boot-Starter: Wie tragen Sie i18n-Nachrichten zur MessageSource bei?

8

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:

%Vor%

Und das wird funktionieren.

Dies erfordert jedoch beides:

  1. Sie müssen die Eigenschaft spring.messages.basename manuell konfigurieren - sie ist nicht automatisch. und
  2. Sie müssen ihre eigene 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?

    
Les Hazlewood 26.02.2015, 18:42
quelle

3 Antworten

2

Vielleicht ist es lang, aber Sie können versuchen, BeanFactoryPostProcessor .

Idee folgt:

  1. 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.

  2. 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.

    
sodik 11.04.2015, 14:47
quelle
15

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

Sehen Sie sich den Code hier an: Code auf github gist

Fügen Sie die Nachrichtenquelle und das Standardgebietsschema Beans

hinzu

Fügen Sie diese Beans zu Ihrer Application.java hinzu, um Ihr Standardgebietsschema festzulegen und den Standort Ihrer Nachrichtenrequisiten zu konfigurieren.

Nachrichtendienst erstellen

Der Dienst erhält das Standardgebietsschema aus der Sitzung und erhält dann den Nachrichtentext von den Requisiten

Verwenden Sie den Nachrichtendienst in Controller

Injizieren Sie die Nachricht svc und geben Sie dann die ID ein, um den Wert aus der Datei reps

zu erhalten

Fügen Sie die Datei message.properties im Gebietsschema

hinzu

Gehe zu / Ressourcen:

  • Erstellen Sie den Gebietsschema-Ordner
  • Erstellen Sie eine Datei namens messages_en_US.properties

Lesen Sie mehr

Sie können einen ausführlicheren Artikel zu diesem Thema hier anzeigen: Spring Boot Internationalisierung i18n mit Nachrichteneigenschaften

Sehen Sie sich den Code an

Sehen Sie sich den Code hier an: Code auf github gist

    
anataliocs 31.05.2015 13:29
quelle
1

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:

%Vor%

Sie können den vollständigen Blogpost lesen, in dem ich einige Vorbehalte zu meiner Lösung erläutere: Ссылка

Aktualisieren

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.

    
Thomas Kåsene 20.08.2016 11:18
quelle