Dokumente sprachabhängig ausliefern mit URL-Rewriting

by Oliver 16. December 2010 16:52

Für das noch relativ neue Premium-Feature auf Camping.Info hat unser Designer und UX-Experte Andrej, der unter friendly-fox.com bloggt, eine Broschüre entworfen, die wir unter www.camping.info/docs/premium-brochure.pdf für Interessenten zum Download anbieten. Da Camping.Info ein vielsprachiges Portal ist, wird auch die Broschüre Schritt für Schritt in andere Sprachen übersetzt. Natürlich wollen wir, dass französischsprachige Nutzer dann die französische Version der Broschüre zu Gesicht bekommen und Spanier die spanische.

Die Lösung, die ich schnell zusammengestellt hatte, um diesen beiden Zielgruppen ihre eigene Version anzubieten, war einfach aber praktisch:

   1:  <% var lang = new List<string> {"ES", "FR"}.Contains(SessionGlobal.LangIso2)
   2:                     ? "-" + SessionGlobal.LangIso2
   3:                     : ""; %>
   4:  <a href="/docs/premium-brochure<%= lang %>.pdf" target="_blank" class="pdf">

Ein bisschen Inline-Serverside-Script und wenn wir auf der spanischen oder französischen Version sind, wird statt /docs/premium-brochure.pdf dann /docs/premium-brochure-es.pdf bzw. /docs/premium-brochure-fr.pdf angezeigt (SessionGlobal.LangIso2 enthält einen zweibuchstabigen Sprachcode).

Wenn wir nur einen solchen Link auf der ganzen Plattform hätten, würde ich diesen Blogpost wohl nicht schreiben – aber wir haben zwei und es sollen noch ein paar mehr werden. Da solcher Code, wenn er auch nur einmal kopiert wird, nach DRY schreit, habe ich mich im Hinblick auf die nächsten Vorkommen und auch die nächsten Sprachen entschieden, eine generische Lösung zu bauen, die die Code-Duplizierung verhindert und gleichzeitig auch noch für weitere Dokumente genutzt werden kann.

Was sollte diese Lösung können?

  1. die händische Anpassung der Liste unterstützer Sprachen überflüssig machen
  2. Code-Duplizierung entfernen
  3. neue Sprachversionen eines Dokumentes automatisch ausliefern, also nichts weiter tun müssen, als neue PDFs mit weiteren Sprach-Kürzeln im /docs-Ordner abzulegen.

 

Eine Option wäre gewesen, den einfachen HTML-Link in einen <asp:HyperLink /> umzuwandeln und ihm serverseitig ein bisschen Logik zu spendieren, die ungefähr so aussehen würde:

  1. Im Dateisystem nachschauen, ob das verlinkte Dokument in der aktuell genutzten Sprache vorhanden ist.
  2. Wenn ja, dann den Link auf dieses Dokument zeigen lassen.
  3. Ansonsten die Standardversion verlinken.

 

Diese Lösung hätte aber wieder Logik in das Code-Behind einer Seite verlegt, die an allen Stellen, an denen ein solcher Link eingebunden werden soll, wiederholt werden müsste. Der Weg aus dieser neuen Redundanz wäre wohl ein kleines UserControl gewesen, dass man dann an beliebiger Stelle hätte einsetzen können. Ich fand aber ein UserControl für einen sprachabhängigen Link irgendwie Overkill, zumal wir es beim nächsten sprachabhängigen PDF hätten genauso machen müssen – neuer Link, neues UserControl. Ganz zu schweigen, von der Logik, die dann dort wieder dupliziert wäre…

Einfacher schien da der Weg über URL-Rewriting zu sein. Wir nutzen das URL-Rewriting-Modul von Albert Weinert und Thomas Bandt mit leichten Modifikationen und einigen selbstgeschriebenen Regeln, und da schien es natürlich, einfach eine weitere für die anstehende Aufgabe zu schreiben. Im Endeffekt sind es 20 Zeilen Code geworden und wir sind gerüstet für die nächsten sprachabhängigen Dokumenten-Links, die völlig transparent vorhandene Sprachversionen ausliefern und für alle anderen Sprachen das Dokument in einer frei konfigurierbaren Sprache zurückliefern.

Die neue Regel macht denn auch nichts anderes:

  1. Sie prüft für die aktuelle Sprache (== Subdomain), ob eine Version des gewünschten Dokuments in dieser vorliegt.
  2. Wenn ja, leitet sie auf diese Datei um.
  3. Wenn nein, wird die Datei in der Default-Sprache, die über die Konfigurationseigenschaft defaultLanguage festgelegt werden kann, ausgeliefert.

 

Die RewriteRule sieht wie folgt aus:

 

Und hier die dazu gehörige Konfiguration:

   1: <add name="LanguageSpecificFiles" provider="ProvLanguageSpecificFile"
   2:      rewrite="Domain"
   3:      virtualUrl="^/docs/.*pdf$" destinationUrl=""
   4:      defaultLanguage="de"
   5:      ignoreCase="true" rewriteUrlParameter="ExcludeFromClientQueryString" />

Einen Kompromiss musste ich bei dieser Lösung eingehen: die Default-Dateiversion muss auch einen Sprach-Suffix bekommen, da wir in der globalen URL-Rewriting-Konfiguration rewriteOnlyVirtualUrls="true" gesetzt haben und so der verwendete Link auf /docs/premium-brochure.pdf überhaupt nicht umgeschrieben würde. Aber das scheint verschmerzbar zu sein.

Wir haben damit jetzt eine Lösung für sprachabhängige Dokumente, die keiner weiteren Pflege bedarf:

  1. einfach Link setzen wie z.B. <a href="/docs/premium-brochure.pdf">Herunterladen</a>
  2. sicherstellen, dass die Datei von der neuen URW-Regel gematcht wird
  3. sprachabhängige Version unter /docs als premium-brochure-de.pdf, premium-brochure-fr.pdf, premium-brochure-it.pdf usw. ablegen
  4. jetzt werden für die Subdomains die jeweiligen Versionen ausgeliefert oder die Defaultversion
  5. die Defaultsprache ist konfigurierbar

Happy Coding,

Oliver

enjoyed the post?

Tags:

Comments are closed

About Oliver

shades-of-orange.com code blog logo I build web applications using ASP.NET and have a passion for javascript. Enjoy MVC 4 and Orchard CMS, and I do TDD whenever I can. I like clean code. Love to spend time with my wife and our children. My profile on Stack Exchange, a network of free, community-driven Q&A sites

About Anton

shades-of-orange.com code blog logo I'm a software developer at teamaton. I code in C# and work with MVC, Orchard, SpecFlow, Coypu and NHibernate. I enjoy beach volleyball, board games and Coke.