<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>meier-online</title>
	<atom:link href="http://meier-online.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://meier-online.com</link>
	<description>Der Blog von Karsten Meier</description>
	<lastBuildDate>Thu, 19 Aug 2010 23:37:38 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>de</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Mehrsprachige Webseiten mit Ruby on Rails (3)</title>
		<link>http://meier-online.com/2010/01/mehrsprachige-webseiten-mit-ruby-on-rails-3/</link>
		<comments>http://meier-online.com/2010/01/mehrsprachige-webseiten-mit-ruby-on-rails-3/#comments</comments>
		<pubDate>Fri, 08 Jan 2010 10:02:16 +0000</pubDate>
		<dc:creator>meier</dc:creator>
				<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Mehrsprachigkeit]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://meier-online.com/?p=656</guid>
		<description><![CDATA[Teil 3 &#8211; Qualitätssicherung
Texte gehören zu den Teilen einer Anwendung, die häufig geändert werden. Wenn dann noch externe Übersetzer im Spiel sind, kann es leicht zu fehlenden Übersetzungen kommen
Wir möchten deshalb automatisch testen, dass es zu allen Texten in Sprache A auch Übersetzungen in Sprache B vorhanden sind. Ein solcher Test allein hilft schon sehr, [...]]]></description>
			<content:encoded><![CDATA[<p>Teil 3 &#8211; Qualitätssicherung</p>
<p>Texte gehören zu den Teilen einer Anwendung, die häufig geändert werden. Wenn dann noch externe Übersetzer im Spiel sind, kann es leicht zu fehlenden Übersetzungen kommen</p>
<p>Wir möchten deshalb automatisch testen, dass es zu allen Texten in Sprache A auch Übersetzungen in Sprache B vorhanden sind. Ein solcher Test allein hilft schon sehr, und sollte ja nicht so schwierig sein.<br />
<span id="more-656"></span></p>
<p>Leider gibt es dabei eine Überraschung: in der Internationalisierung-API findet sich zur Zeit (Rails 2.3.5) keine Möglichkeit, alle Schlüssel aufzuzählen (sprich iterieren). Man muss also offenbar die Yaml-Dateien selbst einlesen, um an die Menge aller definierten Schlüssel zu kommen. Unserer Test wird dabei leider abhängig von der konkreten Art der Datenhaltung.</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">texts_hash = <span style="color:#CC00FF; font-weight:bold;">YAML</span>::<span style="color:#CC0066; font-weight:bold;">load</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#CC00FF; font-weight:bold;">IO</span>.<span style="color:#9900CC;">read</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'config/locales/de.yml'</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span></pre></div></div>

<p>Wie haben nun einen rekursiven Hash. Um alle Schlüssel zu überprüfen, extrahieren wie sie mit einer gesonderten Funktion. Diese Funktion ist einfach rekursiv aufgebaut.<br />
<img src="http://meier-online.com/blog/uploads/rails-i18n-hash.png" alt="Extrahieren der Schlüssel aus einen verschachtelten Hash" title="rails-i18n-hash" width="400" height="240" class="alignnone size-full wp-image-670" /></p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">def</span> deep_hash_key<span style="color:#006600; font-weight:bold;">&#40;</span>hash, prefix<span style="color:#006600; font-weight:bold;">&#41;</span>
  hash.<span style="color:#9900CC;">keys</span>.<span style="color:#9900CC;">sort</span>.<span style="color:#9900CC;">collect</span><span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">|</span>key2<span style="color:#006600; font-weight:bold;">|</span>
    val = hash<span style="color:#006600; font-weight:bold;">&#91;</span>key2<span style="color:#006600; font-weight:bold;">&#93;</span>
    newprefix = prefix.<span style="color:#0000FF; font-weight:bold;">nil</span>? ? key2 : <span style="color:#996600;">&quot;#{prefix}.#{key2}&quot;</span>
    <span style="color:#9966CC; font-weight:bold;">if</span> val.<span style="color:#9900CC;">is_a</span>? <span style="color:#CC00FF; font-weight:bold;">Hash</span>
     deep_hash_key<span style="color:#006600; font-weight:bold;">&#40;</span>val, newprefix<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">else</span>
      newprefix
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#006600; font-weight:bold;">&#125;</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Wollen wir jetzt die Übersetzungen für alle Schlüssel prüfen lauert die Zweite Falle: Wenn die Übersetzung eine Variableninterpolation enthält, erhalten wir einen Fehler beim Aufrufen der translate() Methode ohne den passenden Hash. Offenbar liefert uns die API auch keinen Zugriff auf den String ohne Interpolierung. Da uns in diesen Test nur die Existenz einer Übersetzung interessiert, und nicht ihr konkreter Wert, fangen wir die Exception &#8220;MissingInterpolationArgument&#8221; einfach auf.</p>
<p>Für eine deutsche Anwendung mit Übersetzungen in Englisch und Französisch sieht dann der Test so aus:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">def</span> test_all_texts_should_exists
  texts_hash = <span style="color:#CC00FF; font-weight:bold;">YAML</span>::<span style="color:#CC0066; font-weight:bold;">load</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#CC00FF; font-weight:bold;">IO</span>.<span style="color:#9900CC;">read</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'config/locales/de.yml'</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
  de_keys = deep_hash_key<span style="color:#006600; font-weight:bold;">&#40;</span>texts_hash<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'de'</span><span style="color:#006600; font-weight:bold;">&#93;</span>, <span style="color:#0000FF; font-weight:bold;">nil</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">flatten</span>
  <span style="color:#9966CC; font-weight:bold;">for</span> lang <span style="color:#9966CC; font-weight:bold;">in</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'de'</span>, <span style="color:#996600;">'fr'</span>, <span style="color:#996600;">'en'</span><span style="color:#006600; font-weight:bold;">&#93;</span>
    I18n::locale = lang
    <span style="color:#9966CC; font-weight:bold;">for</span> key <span style="color:#9966CC; font-weight:bold;">in</span> de_keys
      <span style="color:#9966CC; font-weight:bold;">begin</span>
        val = I18n.<span style="color:#9900CC;">translate</span><span style="color:#006600; font-weight:bold;">&#40;</span>key, <span style="color:#ff3333; font-weight:bold;">:default</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">nil</span>, <span style="color:#ff3333; font-weight:bold;">:raise</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span><span style="color:#006600; font-weight:bold;">&#41;</span>
      <span style="color:#9966CC; font-weight:bold;">rescue</span> <span style="color:#6666ff; font-weight:bold;">I18n::MissingTranslationData</span>
        val = <span style="color:#0000FF; font-weight:bold;">nil</span>
      <span style="color:#9966CC; font-weight:bold;">rescue</span> <span style="color:#6666ff; font-weight:bold;">I18n::MissingInterpolationArgument</span>
        val = <span style="color:#0000FF; font-weight:bold;">true</span>  <span style="color:#008000; font-style:italic;"># there was a value, only an argument is missing</span>
      <span style="color:#9966CC; font-weight:bold;">end</span>
      assert_not_nil<span style="color:#006600; font-weight:bold;">&#40;</span>val, <span style="color:#996600;">&quot;key missing for locale #{lang}: #{key}&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Wenn jetzt eine Übersetzung fehlt, liefert der Test eine Fehlermeldung der Art:</p>
<pre>
test_all_texts_should_exists(LocalisationTest): key missing for locale en: users.edit.title</pre>
<p>Die fehlende Übersetzung können wir dann ergänzen, bevor wir eine neue Version der Anwendung veröffentlichen. </p>
]]></content:encoded>
			<wfw:commentRss>http://meier-online.com/2010/01/mehrsprachige-webseiten-mit-ruby-on-rails-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Classics reloaded: Das Assert-Makro von C</title>
		<link>http://meier-online.com/2009/09/assert/</link>
		<comments>http://meier-online.com/2009/09/assert/#comments</comments>
		<pubDate>Sun, 20 Sep 2009 14:41:43 +0000</pubDate>
		<dc:creator>meier</dc:creator>
				<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Assert]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[Qualitätswerkzeug]]></category>

		<guid isPermaLink="false">http://meier-online.com/?p=618</guid>
		<description><![CDATA[Die erste Version des folgenden Textes stammt noch aus dem Jahr 1996. Er enstand, weil ich bei den damaligen Arbeitgebern beobachtete, dass viele C-Entwickler nicht wussten, was es mit assert() auf sich hat. Hier kommt die Wiederveröffentlichung:
Selbstidentifizierende Fehler
Es gibt in ANSI-C einen Mechanismus, viele Fehler auch ohne Debugger aufzuspüren: Das Assert Macro. Ein Teil des [...]]]></description>
			<content:encoded><![CDATA[<p>Die erste Version des folgenden Textes stammt noch aus dem Jahr 1996. Er enstand, weil ich bei den damaligen Arbeitgebern beobachtete, dass viele C-Entwickler nicht wussten, was es mit assert() auf sich hat. Hier kommt die Wiederveröffentlichung:</p>
<h3>Selbstidentifizierende Fehler</h3>
<p>Es gibt in ANSI-C einen Mechanismus, viele Fehler auch ohne Debugger aufzuspüren: Das Assert Macro. Ein Teil des Problems liegt in Deutschland wohl auch im Namen: Assert ist ein Wort, welches im allgemeinen im Englisch an der Schule nicht benutzt wird.</p>
<p><span id="more-618"></span>Meine Übersetzung hierfür lautet Zusicherung. Das Assert Macro prüft diese Zusicherung, und druckt, falls es schief geht, seine eigene Datei mit Zeilennummer im Quelltext aus. Ein Beispiel:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> readFile<span style="color: #009900;">&#40;</span>
    <span style="color: #993333;">char</span> <span style="color: #339933;">*</span> filename
    <span style="color: #993333;">char</span> <span style="color: #339933;">*</span> buffer
<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> filehandle<span style="color: #339933;">;</span>
    assert<span style="color: #009900;">&#40;</span> filename <span style="color: #339933;">!=</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    assert<span style="color: #009900;">&#40;</span>strlen<span style="color: #009900;">&#40;</span>filename<span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    assert<span style="color: #009900;">&#40;</span>strlen<span style="color: #009900;">&#40;</span>filename<span style="color: #009900;">&#41;</span> <span style="color: #339933;">&lt;</span> MAX_FILENAMELEN<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    filehandle <span style="color: #339933;">=</span> open<span style="color: #009900;">&#40;</span>filename<span style="color: #339933;">,</span> READ_ONLY<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    ...
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Falls jetzt irgend jemand meine Funktion mit falschen Parametern aufruft, z.B. mit einem leeren String, passiert während des Programlaufes folgendes:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">assertion failed in file readfile.c, line 34:
strlen(filename) &gt; 0
program aborted</pre></div></div>

<p>Der Tester, wer immer das ist, kann in der angegebenen Datei die Zeile aufspüren, in der der Fehler auftrat, und erfährt dann, dass die Funktion readFile mit einem Leerstring aufgerufen wurde. Oft hat man damit schon die Fehler gefunden, in den anderen Fällen hat man zumindestens einen Anhaltspunkt.</p>
<p>Frage: <em>Sollte man nicht eine wasserdichte Fehlerbehandlung machen?</em></p>
<p>Welcome to Reality! Die obige Lösung ist ein Einzeiler. In der Praxis bedeutet dieses: Ein assert() schreibt man auch hin, wenn man meint, das ein bestimmter Fall in der Praxis nie und nimmer auftreten wird. Im obigen Beispiel ist der Programmierer der Aufruffunktion dazu verflichtet, der Funktion einen Buffer zur Verfügung zu stellen. Wenn der Buffer bei NULL liegt, hat er Mist gemacht. Bei der Länge des Filenames kommt es auf die Anwendung an: Falls hier ein vom Endbenutzer eingegebener String direkt benutzt wird, ist die assert Lösung allenfalls während der Prototypphase erlaubt.</p>
<p>Die Fehler, von denen man damit rechnet, dass sie während des normalen Betriebes auftreten, sollte man selbstverständlich auch korrekt abfangen.</p>
<p>Das Assert hat auch seinen Sinn, wenn es nicht feuert: Bei einer Fehlersuche kann ich sicher sein, dass ein bestimmtes Problem nicht aufgetreten ist, dass ich den Fehler also woanders suchen muss.</p>
<p>Nicht zuletzt teile ich den armen Leuten, die mein Programm einmal warten müssen, etwas über meine Intention mit: Der Pointer darf kein NULL-Pointer sein, der Dateiname soll weniger als X Buchstaben haben, &#8230; Das alles kann man auch in die Kommentare schreiben, aber nur Code lügt nicht.</p>
<p>Frage: <em>In C++ und Java gibt es doch den Exception Mechanismus.</em></p>
<p>Ja der ist oft noch besser, aber leider auch noch etwas komplizierter. Vieles, was ich gesagt habe, läßt sich auch auf diesen Mechanismus übertragen. Leider kann man sich auch nicht immer aussuchen, in welcher Sprache man programmiert.</p>
<p>Frage: <em>Wenn diese Fehlermeldung dann im laufenden Betrieb beim Kunden auftritt, ist das doch eher peinlich. Und das Programm wird doch bestimmt größer und langsamer? Das heisst doch, nacher muß ich alle asserts() wieder rausnehmen?</em></p>
<p>Zum Glück nicht! Das Assert läßt sich durch einen Compilerschalter aktivieren oder deaktivieren. Wenn in irgendeiner Headerdatei steht:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#define NDEBUG</span></pre></div></div>

<p>oder in der Makedatei:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">-DNDEBUG</pre></div></div>

<p>so wird für das Assert kein Code erzeugt, so als ob man alle assert Zeilen rausediert hätte.</p>
<p>Frage: <em>Wie funktioniert das eigentlich?</em></p>
<p>Das Geheimnis liegt im Zusammenspiel von Preprocessor und Compiler. Das Assert ist als Macro implementiert, im allgemeinen in der Datei assert.h. Das Grundgerüst ist folgendes:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#ifdef NDEBUG</span>
<span style="color: #339933;">#define assert(exp)</span>
<span style="color: #339933;">#else</span>
<span style="color: #339933;">#define assert(exp) \
 ( (exp) ? (void) 0 : _assert(#exp, __FILE__, __LINE__))</span>
<span style="color: #339933;">#endif</span></pre></div></div>

<p>Das sieht doch reichlich kryptisch aus, ist jedoch gar nicht so kompliziert: Macros sind Textersetzer. Mittels #ifdef&#8230;#else&#8230;#endif wird dafür gesorgt, das nur Code erzeugt wird, falls das Symbol NDEBUG nicht definiert ist. Dann wird nämlich assert zusammen mit seinen Argument durch einen leeren String ersetzt, der Compiler bekommt die betreffenden Zeilen nicht einmal zu Gesicht. Im Debugfall setzt der Compiler die Wörter __FILE__ und __LINE__ durch die aktuelle Quelldatei (nicht iassert.h, sondern die Datei der Aufrufstelle) und die aktuelle Zeilennummer. Der Ausdruck #exp wird durch den aktuellen Ausdruck als String ersetzt.</p>
<p>Die eigenartige Klammerstruktur (xxx ? yyy : zzz) gehört zum normalen C Sprachumfang, wird jedoch von wohlerzogenen Programmierern nur in Ausnahmefällen wie diesen verwendet. Es ist etwas wie ein verkürztes if-statement. Die Backslashes am Ende der Zeile verlängern die Zeilen, da der Macromechanismus ausschließlich zeilenorientiert arbeitet. Insgesamt erzeugt der Preprozessor aus der Zeile</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">assert<span style="color: #009900;">&#40;</span>strlen<span style="color: #009900;">&#40;</span>filename<span style="color: #009900;">&#41;</span> <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>die Zeile</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span>strlen<span style="color: #009900;">&#40;</span>filename<span style="color: #009900;">&#41;</span> <span style="color: #339933;">&gt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">?</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span> <span style="color: #0000dd;">0</span> <span style="color: #339933;">:</span> _assert<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;strlen(filename &gt; 0&quot;</span><span style="color: #339933;">,</span> __FILE__<span style="color: #339933;">,</span> __LINE__<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Die tief im Inneren einer Library definierte Funktion _assert() gibt die Argumente, z.B. mit printf(), auf den Bildschirm aus und bricht das Programm ab.</p>
<p>Frage: <em>Alles schön und gut, aber ich programmiere mit einem Fenstersystem, manchmal programmiere ich auch Anwendungen ganz ohne Bildschirm. Was nun?</em></p>
<p>Viele Benutzer haben Glück: In einigen Entwicklungsumgebungen gibt es ein assert(), das ein Pop-up-Fenster öffnet. Ansonsten lohnt es sich für solche Fälle, ein assert-Macro selbst zu schreiben.  Das prinzipielle Vorgehen ist dabei, eine Ausgabefunktion zu schreiben, die die betreffende Ausgabe irgendwohin ausgibt, die Datei assert.h zu kopieren und statt des _assert die eigene Ausgabefunktion aufzurufen. Die Ausgabe kann in eine Logdatei, über die Soundschnittstelle, als Email, als Fax, oder als was auch immer erfolgen.</p>
<p>Ähnlich ist auch in anderen Programmiersprachen zu verfahren. Meistens bieten die Hersteller irgendeine Entsprechung zu __FILE__ und __LINE__ an, selbst wenn es nicht im offiziellen Sprachstandard ist.</p>
<p>Frage: <em>Das ist ja toll, was man mit Macros alles machen kann, ich habe da gerade eine Idee &#8230;</em></p>
<p>Vorsicht: Wer Macros einsetzt, nur um ein paar Zeilen Code zu sparen, wird es irgendwann bitter bereuen.</p>
<p>Ich habe mal bei einer Firma ein Macro entdeckt, das dazu dienen sollte, Teile eines Records in einen anderen zu kopieren. Dieses Macro war schon mehrere Jahre bei dieser Firma im Einsatz, leider war es nur manchmal korrekt. Ich habe mit mehreren anderen Entwicklern lange vor dem Macro gesessen, um herausfinden, was es eigentlich tat. Es arbeitete ganz gut. Je nach dem, mit welchem Record man es aufrief, überschrieb es jedoch einen verbotenen Speicherbereich. Das Macro war bestimmt für etliche Abstürze verantwortlich, auch bei ausgelieferten Systemen. Die Firma war übrigens kurze Zeit später pleite &#8230;</p>
<h3>Zurück ins Jahr 2009</h3>
<p>Im Jahr 2009 werden Assert-Methoden oft in Unit-Tests verwendet. Dagegen ist auch nichts einzuwenden. Beim vorliegenden Text ging es mir aber um etwas anderes: die Verwendung von Assert im Programmtext selber. Diese Asserts können auch bei unerwarteten Fehler helfen. Sie sind auch allgemeiner: Sie prüfen Aussagen über das Programm, die immer gelten sollen, nicht nur bei bestimmten Testdaten. Asserts im Programmtext selbst sind deshalb auch bei Nutzung von Unittests nützlich.</p>
]]></content:encoded>
			<wfw:commentRss>http://meier-online.com/2009/09/assert/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rotierende Reklametafel mit jQuery</title>
		<link>http://meier-online.com/2009/08/rolling-billboard-jquery/</link>
		<comments>http://meier-online.com/2009/08/rolling-billboard-jquery/#comments</comments>
		<pubDate>Fri, 21 Aug 2009 17:15:05 +0000</pubDate>
		<dc:creator>meier</dc:creator>
				<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Reklametafel]]></category>

		<guid isPermaLink="false">http://meier-online.com/?p=584</guid>
		<description><![CDATA[Im Jahre 1998 habe ich &#8220;Meiers Billboard&#8221; vorgestellt: Eine virtuelle Anzeigentafel, die Bilder durch Rollen austauscht. Technisch ist es ein Java Applet. Der Ruf von Java im Browser wurde immer schlechter, auch mein Applet war vor allem wegen des Bild des Rahmen verlinkt.
In der Zwischenzeit ist sind die Netze leistungsfähiger, die Rechner schneller geworden und [...]]]></description>
			<content:encoded><![CDATA[<p>Im Jahre 1998 habe ich &#8220;<a title="Die Vorstellung des Applets von 1998" href="/develop/java/billboardlight/index.html">Meiers Billboard</a>&#8221; vorgestellt: Eine virtuelle Anzeigentafel, die Bilder durch Rollen austauscht. Technisch ist es ein Java Applet. Der Ruf von Java im Browser wurde immer schlechter, auch mein Applet war vor allem wegen des Bild des Rahmen verlinkt.</p>
<p>In der Zwischenzeit ist sind die Netze leistungsfähiger, die Rechner schneller geworden und dank CSS gibt es neue Gestaltungsmittel. Bei der Beschäftigung mit dem JavaScript-Framework &#8220;<a title="Zur offiziellen Seite des jQuery Projektes" href="http://www.jquery.com" target="_blank">jQuery</a>&#8220;  stieß ich auf die animate()-Methode und ich fragte mich: lässt sich das Billboard nicht auch mit JavaScript realisieren?<span id="more-584"></span></p>
<p><img class="alignnone size-full wp-image-594" title="Funktionsweise: Eine Liste von Bildern wird unter einem Fenster hindurchgeschoben." src="http://meier-online.com/blog/uploads/billboardschema.png" alt="Funktionsweise: Eine Liste von Bildern wird unter einem Fenster hindurchgeschoben." width="360" height="280" /></p>
<p>Die Grundidee ist einfach: Es gibt einen Rahmen und eine Liste von Bildern. Wir manipulieren die &#8220;top&#8221;-Koordinate der Liste, um die Bewegung zu erzeugen. Die Clipping-Eigenschaft bewirkt, dass wir nur das Innere des Rahmens sehen.</p>
<p>Der HTML-Code besteht somit im wesentlichen aus einer Liste:</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt; div id=&quot;billboard&quot;&gt;
&lt;ul&gt;
 &lt;li&gt;&lt;a href=&quot;link1&quot;&gt;&lt;img src=&quot;img1&quot; ... &gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href=&quot;link2&quot;&gt;&lt;img src=&quot;img2&quot; ... &gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href=&quot;link3&quot;&gt;&lt;img src=&quot;img3&quot; ... &gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href=&quot;link1&quot;&gt;&lt;img src=&quot;img1&quot; ...&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;</pre></div></div>

<p>Anders als bei einer Lösung mit Java-Applet (oder auch Flash) haben wir alle Auszeichnungsmöglichkeiten von HTML zur Verfügung. Die Bilder und Links können wir beispielsweise suchmaschinenfreundlich mit title-Attributen versehen. Die Bilder müssen alle die gleiche Größe haben und werden mit Hilfe von css in das Bild eines Rahmens positioniert:</p>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;">  <span style="color: #cc00cc;">#billboard</span><span style="color: #00AA00;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">width</span><span style="color: #00AA00;">:</span> <span style="color: #933;">260px</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">height</span><span style="color: #00AA00;">:</span>  <span style="color: #933;">264px</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">background-image</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">url</span><span style="color: #00AA00;">&#40;</span><span style="color: #ff0000; font-style: italic;">Rahmen.jpg</span><span style="color: #00AA00;">&#41;</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">position</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">relative</span><span style="color: #00AA00;">;</span>
    <span style="color: #000000; font-weight: bold;">padding</span><span style="color: #00AA00;">:</span> <span style="color: #933;">0px</span><span style="color: #00AA00;">;</span>
  <span style="color: #00AA00;">&#125;</span>
  <span style="color: #cc00cc;">#billboard</span> ul<span style="color: #00AA00;">&#123;</span>
     <span style="color: #000000; font-weight: bold;">list-style</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">none</span><span style="color: #00AA00;">;</span>
     <span style="color: #000000; font-weight: bold;">padding</span><span style="color: #00AA00;">:</span> <span style="color: #933;">0px</span><span style="color: #00AA00;">;</span>
     <span style="color: #000000; font-weight: bold;">margin</span><span style="color: #00AA00;">:</span> <span style="color: #933;">0px</span><span style="color: #00AA00;">;</span>
     <span style="color: #000000; font-weight: bold;">position</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">absolute</span><span style="color: #00AA00;">;</span>
     <span style="color: #000000; font-weight: bold;">top</span><span style="color: #00AA00;">:</span> <span style="color: #933;">30px</span><span style="color: #00AA00;">;</span>
     <span style="color: #000000; font-weight: bold;">left</span><span style="color: #00AA00;">:</span> <span style="color: #933;">29px</span><span style="color: #00AA00;">;</span>	
     <span style="color: #000000; font-weight: bold;">clip</span><span style="color: #00AA00;">:</span> rect<span style="color: #00AA00;">&#40;</span><span style="color: #933;">0px</span>  <span style="color: #933;">200px</span> <span style="color: #933;">200px</span> <span style="color: #933;">0px</span><span style="color: #00AA00;">&#41;</span><span style="color: #00AA00;">;</span>	
  <span style="color: #00AA00;">&#125;</span>
    ...</pre></div></div>

<h3>Verschieben</h3>
<p>Eine Methode zum Verschieben ist dank jQuery sehr einfach:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> simple_move_up<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
	$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#billboard ul li'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">animate</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>top<span style="color: #339933;">:</span> <span style="color: #3366CC;">'-200px'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3000</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p style="margin-bottom: 0cm;">Etwas komplizierter wird es dadurch, dass wir nach dem letzten Bild nahtlos wieder das erste wieder zeigen wollen. Hier gibt es einen Trick: Für den nahtlosen Übergang wiederholen wir in der HTML-Liste nach den letzten Bild noch einmal das erste. Wenn nun das neue letzte Bild erreicht ist, können wir zum ersten Bild springen, ohne das es bemerkt wird.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> picth <span style="color: #339933;">=</span> <span style="color: #CC0000;">200</span><span style="color: #339933;">;</span>		<span style="color: #009966; font-style: italic;">/* height of a single picture */</span>
<span style="color: #003366; font-weight: bold;">var</span> nr_picts <span style="color: #339933;">=</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> curpos <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">function</span> move_up<span style="color: #009900;">&#40;</span>ydiff<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
	curpos <span style="color: #339933;">=</span> curpos <span style="color: #339933;">-</span> picth<span style="color: #339933;">;</span>
	<span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>curpos <span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span> nr_picts <span style="color: #339933;">*</span> picth<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
		curpos <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
		$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#billboard ul li'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">css</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>top<span style="color: #339933;">:</span> curpos<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		curpos <span style="color: #339933;">=</span> curpos <span style="color: #339933;">-</span> picth<span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
 	$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#billboard ul li'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">animate</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>top<span style="color: #339933;">:</span> curpos<span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3000</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<h3>Endlosschleife</h3>
<p>Jetzt bleibt nur noch, unsere move_up Methode in regelmäßigen Abständen aufzurufen.</p>
<p>Dazu setzen wir eine (anonyme) Funktion, die JQuery bei abgeschlossenen Aufbau des Dokumentes aufruft. In dieser rufen wir die Funktion setInterval() aus dem JavaScript-Standard auf.</p>
<p>Bei dem Timing-Parameter müssen wir aufpassen: Der Parameter beschreibt nicht die Zeit zwischen den Animationen, sondern die Gesamtzeit eines Zyklus. Im Beispiel sind dies 8 Sekunden bzw. 8000 Millisekunden, nämlich 3 Sekunden für die Animation und 5 Sekunden Pause.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span>document<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">ready</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
	setInterval<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;move_up(-200)&quot;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">8000</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p>Damit funktioniert das Billboard dank jQuery mit erstaunlich wenigen Codezeilen.</p>
<p>Zur Demoseite mit der <a href="/develop/jquery/billboard.html" target="_blank">rotierenden Reklametafel</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://meier-online.com/2009/08/rolling-billboard-jquery/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google Technology User Group Hamburg</title>
		<link>http://meier-online.com/2009/06/gtug-hamburg-appengine-mapplet/</link>
		<comments>http://meier-online.com/2009/06/gtug-hamburg-appengine-mapplet/#comments</comments>
		<pubDate>Sun, 28 Jun 2009 15:15:54 +0000</pubDate>
		<dc:creator>meier</dc:creator>
				<category><![CDATA[IT-Szene]]></category>
		<category><![CDATA[AppEngine]]></category>
		<category><![CDATA[Gadgets]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Mapplet]]></category>

		<guid isPermaLink="false">http://meier-online.com/?p=504</guid>
		<description><![CDATA[Erstes Treffen mit den Themen AppEngine, Mapplets und Gadgets.
[29dsnh4p5a] Am 23. Juni fand das erste Treffen der Google User Group Hamburg statt. Sie beschäftigt sich mit der Vielzahl der Technologien jenseits einer einfachen Suche, die Google inzwischen zur Nutzung auch für eigene Projekte anbietet.
Die Firma &#8220;eprofessional&#8221; stellte an diesem Abend den Raum und netterweise auch [...]]]></description>
			<content:encoded><![CDATA[<h4>Erstes Treffen mit den Themen AppEngine, Mapplets und Gadgets.</h4>
<p>[29dsnh4p5a] Am 23. Juni fand das <a href="http://www.hamburg-gtug.org/2009/05/24-juni-app-engine-gadgets-und-maplets.html">erste Treffen</a> der Google User Group Hamburg statt. Sie beschäftigt sich mit der Vielzahl der Technologien jenseits einer einfachen Suche, die Google inzwischen zur Nutzung auch für eigene Projekte anbietet.<br />
Die Firma <a href="http://www.eprofessional.de">&#8220;eprofessional&#8221;</a> stellte an diesem Abend den Raum und netterweise auch die Getränke. <span id="more-504"></span></p>
<p>Im ersten Teil des Abends stellte Jens Trapp die AppEngine und speziell die Nutzung mit Java vor.<br />
Die AppEngine nutzt nicht eine &#8220;normale&#8221; relationale Datenbank, sondern die speziellen Datastores von Google zur manchmal über die ganze Erde verteilten Speicherung großer Datenmengen. Um die Anpassung bestehender Software zu vereinfachen, ist für einfache Fälle auch eine Abfrage in SQL-Syntax möglich. Einen ähnlicher Weg ist mir auch von der nativen Symbianentwiclung bekannt. Mich persönlich überzeugt das nicht richtig. SQL ist eine interpretierte Sprache. Wird sie von einer statisch typisierten, compilierten Sprache wie Java oder C++ aufgerufen, verbindet man die Nachteile beider Konzepte, ohne die Vorzüge zu genießen. Man verliert die Typsicherheit, riskiert sogar noch Sicherheitslücken (SQL-Injektion), kann andererseits nicht die wunderbaren Eigenschaften einer kompletten SQL-Implementierung nutzen.</p>
<p>Im zweiten Teil stellte Thomas Steiner &#8220;<a href="http://code.google.com/apis/maps/documentation/mapplets/">Mapplets</a>&#8221; und ihre technologischen Verwandten &#8220;Gadgets&#8221; vor. Gadgets können per Javascript auch Webservices aufrufen, dabei werden auch die Sicherheitsrichtlinien der Browser beachtet. Die Gadgets können neben der iGoogle-Webseite auch in anderen Kontexten aufgerufen werden und sogar als Suchmaschinenanzeigen geschaltet werden. Als nettes Beispiel wurde eine Anzeige präsentiert, die bei Sonnenschein oder bei Regen jeweils verschiedene Angebote darstellt.</p>
<p>Zum offiziellen Blog der <a href="http://www.hamburg-gtug.org">Google Technology User Group Hamburg</a></p>
]]></content:encoded>
			<wfw:commentRss>http://meier-online.com/2009/06/gtug-hamburg-appengine-mapplet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mehrsprachige Webseiten mit Ruby on Rails (2)</title>
		<link>http://meier-online.com/2009/05/localize-ruby-on-rails-p2/</link>
		<comments>http://meier-online.com/2009/05/localize-ruby-on-rails-p2/#comments</comments>
		<pubDate>Tue, 12 May 2009 13:51:47 +0000</pubDate>
		<dc:creator>meier</dc:creator>
				<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Mehrsprachigkeit]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Validierungen]]></category>

		<guid isPermaLink="false">http://meier-online.com/?p=422</guid>
		<description><![CDATA[Teil 2 &#8211; Platzhalter, Validierungen, Modellklassen
[Zu Teil 1]
Oft enthalten Webseiten Sätze, in denen sich ein einzelnes Wort sich dynamisch ändert. Beispielsweise &#8220;Sie sind als xxxx eingeloggt.&#8221; Zur Übersetzung können wir natürlich den Satz aus seinen Bestandteilen zusammenzubauen. Oft gibt es ein Problem: in verschiedenen Sprachen ist der Satzbau anders.
Besser ist deshalb die sogenannte Interpolation, wie [...]]]></description>
			<content:encoded><![CDATA[<h3>Teil 2 &#8211; Platzhalter, Validierungen, Modellklassen</h3>
<p>[<a href="/2009/04/localize-ruby-on-rails/">Zu Teil 1</a>]</p>
<p>Oft enthalten Webseiten Sätze, in denen sich ein einzelnes Wort sich dynamisch ändert. Beispielsweise &#8220;Sie sind als xxxx eingeloggt.&#8221; Zur Übersetzung können wir natürlich den Satz aus seinen Bestandteilen zusammenzubauen. Oft gibt es ein Problem: in verschiedenen Sprachen ist der Satzbau anders.</p>
<p>Besser ist deshalb die sogenannte Interpolation, wie man sie in Ruby ja kennt. Im Satz steht ein markierter Platzhalter, der zur Laufzeit ersetzt wird. Die yaml-Datei zur Spezifikation nutzt hierbei nicht die Ruby Syntax, sondern markiert die zu ersetzenden durch doppelte geschweifte Klammern. Achtung: In Rails 3 hat sich die Syntax leicht geändert.</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#008000; font-style:italic;"># Definition</span>
  logmsg: <span style="color:#996600;">&quot;Sie sind als {{name}} eingeloggt.&quot;</span>
<span style="color:#008000; font-style:italic;"># Definition in Rails 3</span>
  logmsg: <span style="color:#996600;">&quot;Sie sind als %{name} eingeloggt.&quot;</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># Aufruf</span>
I18n.<span style="color:#9900CC;">translate</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:logmsg</span>, <span style="color:#ff3333; font-weight:bold;">:name</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'Administrator'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#008000; font-style:italic;"># oder in kurz</span>
t <span style="color:#ff3333; font-weight:bold;">:logmsg</span>, <span style="color:#ff3333; font-weight:bold;">:name</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'Administrator'</span></pre></div></div>

<p>Wir müssen dabei sicherstellen, das die Parameter von Definition und Aufruf übereinstimmen. Die <em>translate()</em>-Methode dabei relativ tolerant: Überflüssige Parameter werden ignoriert, fehlende Parameter werden mit einem &#8220;(???)&#8221; ersetzt.</p>
<p> <img src='http://meier-online.com/blog/wp-includes/images/smilies/icon_exclaim.gif' alt=':!:' class='wp-smiley' />  Achtung: die übersetzende Person muss wissen, dass sie die Variablennamen in den Klammern nicht mit übersetzen soll!<br />
Eine weitere kleine Falle lauert bei den Variablennamen: Sie dürfen nicht wie eine der anderen Parameter der <em>translate()</em>-Methode heißen. Verboten sind deshalb &#8220;default&#8221; und &#8220;scope&#8221;.</p>
<p><span id="more-422"></span></p>
<h3>Texte der Validierungen</h3>
<p>Selbst wenn wir unsere Applikation nur einsprachig auf deutsch erstellen, gibt es an einer Stelle eine Überraschung: bei den automatisch generierten Fehlermeldungen der Validierungen in den Model-Klassen. Sehr praktisch, aber dummerweise in Englisch. Außerdem setzen sie die Klassennamen und Attributnamen direkt ein. Die Namen der Klassen und Attribute wählen wir normalerweise nach den Bedürfnissen der Programmierer, für die Benutzer sind gelegentlich andere Vokabeln angebrachter.</p>
<p>Der Aufbau einer Fehlermeldung bei einer fehlgeschlagenen Validierung ist im Bild zu sehen:</p>
<p><img class="alignnone size-full wp-image-444" title="Zusammenbau der Übersetzung von Fehlermeldungen der Model-Validierunegn in Rails" src="http://meier-online.com/blog/uploads/rails-fehlermeldungen-ersetzung400.png" alt="Zusammenbau der Übersetzung von Fehlermeldungen der Model-Validierungen in Rails" width="420" height="212" /></p>
<p>Zur Anzeige auf Deutsch müssen wir die Texte nur mit den richtigen Schlüsseln in unsere yaml-Übersetzungdatei eintragen. Die Rumpfsätze sind im Bereich (scope) <em>activerecord.messages</em> definiert. Da diese Sätze für alle Anwendungen gleich sind, gibt es schon für viele Sprachen und auch für Deutsch schon Standardübersetzungen.</p>
<h4>Übersetzung des Models</h4>
<p>Die Namen der Felder und Objekte müssen wir in der yaml-Datei im Bereich <em>activerecord.models.classname</em> beziehungsweise  <em>activerecord.attributs.classname.attributname</em> definieren. Dann erkennt sie Rails und setzt sie korrekt in die automatischen Validierungsmeldungen ein.<br />
Die zentrale Übersetzung der Klassennamen und Feldernamen ist auch für die Views interessant. So brauchen wir die Labels von Eingabefeldern nicht ein zweites oder drittes mal übersetzen.</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">activerecord:
  models:
    term: &quot;Begriff&quot;
  attributes:
    term:
      name: &quot;Name&quot;
      topic: &quot;Sachgebiet&quot;</pre></div></div>

<p>Das macht für die Views nicht immer Sinn. Die Benutzerschnittstelle sollte sich nicht zu eng an das Model halten. Wichtig ist ja schliesslich der Benutzer.</p>
<h3>Validierungen mit eigenen Meldungen</h3>
<p>Ein typischer Anwendungsfall für eine eigene Meldung ist die Überprüfung einer Telefonnummer. Die Methoden zur Spezifikation der Validierungen haben einen Parameter &#8220;message&#8221;. Damit sollte eine Übersetzung ja kein Problem sein: Wir sollten einfach hier die t()-Methode aufrufen können. Leider klappt es so nicht:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#008000; font-style:italic;"># funktioniert so nicht! Does not work!</span>
validates_format_of<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:fax</span>,<span style="color:#006600; font-weight:bold;">&#123;</span>
    <span style="color:#ff3333; font-weight:bold;">:with</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">/</span>\A<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">0</span><span style="color:#006600; font-weight:bold;">-</span><span style="color:#006666;">9</span> \<span style="color:#006600; font-weight:bold;">+</span>\<span style="color:#006600; font-weight:bold;">-</span>\<span style="color:#006600; font-weight:bold;">/</span>\<span style="color:#006600; font-weight:bold;">&#40;</span>\<span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">+</span>\Z<span style="color:#006600; font-weight:bold;">/</span>i,
    <span style="color:#ff3333; font-weight:bold;">:message</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> t<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'activerecord.errors.messages.bad_phone'</span><span style="color:#006600; font-weight:bold;">&#41;</span>,
    <span style="color:#ff3333; font-weight:bold;">:allow_blank</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span></pre></div></div>

<p>Je nach Version und des verwendeten Deployments startet Rails gar nicht erst hoch oder liefert die gewünschte Übersetzung nicht. Was läuft schief?</p>
<p>Die Sprache ist ja immer pro Request gesetzt. Bei der Definition der deklarativen Valdierungen im Model gibt es noch gar keinen Request! Es macht deshalb keinen Sinn zu diesen Zeitpunkt die translate-Methode aufzurufen.</p>
<p>Aber wie lösen wir das Problem? Typisch für Rails ist die Lösung schon eingebaut. Wenn man sie nicht kennt, kann man sich allerdings lange im Kreis drehen.<br />
Wir können dem message &#8211; Parameter nämlich auch ein Symbol statt eines Strings mitgeben: das Symbol wird erst ausgewertet, wenn die Fehlermeldung angezeigt werden soll. Das Symbol wird nacheinander in diesen speziellen Kontexten (scope) ausgewertet:</p>
<ul>
<li>activerecord.errors.models.[model_name].attributes.[attribute_name]</li>
<li>activerecord.errors.models.[model_name]</li>
<li>activerecord.errors.messages</li>
</ul>
<p>Unsere Validierung können wir demnach einfach so schreiben:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">validates_format_of<span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#ff3333; font-weight:bold;">:fax</span>,<span style="color:#006600; font-weight:bold;">&#123;</span>
    <span style="color:#ff3333; font-weight:bold;">:with</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">/</span>\A<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">0</span><span style="color:#006600; font-weight:bold;">-</span><span style="color:#006666;">9</span> \<span style="color:#006600; font-weight:bold;">+</span>\<span style="color:#006600; font-weight:bold;">-</span>\<span style="color:#006600; font-weight:bold;">/</span>\<span style="color:#006600; font-weight:bold;">&#40;</span>\<span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">+</span>\Z<span style="color:#006600; font-weight:bold;">/</span>i,
    <span style="color:#ff3333; font-weight:bold;">:message</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:bad_phone</span>,
    <span style="color:#ff3333; font-weight:bold;">:allow_blank</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span></pre></div></div>

<h4>Quellen:</h4>
<p>Beschreibung (Guide) der Internationalization API:<br />
<a href="http://guides.rubyonrails.org/i18n.html">guides.rubyonrails.org/i18n.html</a></p>
<p>Sprachdateien für Standardübersetzungen:<br />
<a href="http://guides.rubyonrails.org/i18n.html">github.com/svenfuchs/rails-i18n/tree/master/rails/locale</a></p>
<p><a href="/2010/01/mehrsprachige-webseiten-mit-ruby-on-rails-3/">Zu Teil 3 dieses Artikels</a></p>
]]></content:encoded>
			<wfw:commentRss>http://meier-online.com/2009/05/localize-ruby-on-rails-p2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>SQL: Feld aus verknüpfter Tabelle setzen</title>
		<link>http://meier-online.com/2009/05/sql-update-join/</link>
		<comments>http://meier-online.com/2009/05/sql-update-join/#comments</comments>
		<pubDate>Mon, 04 May 2009 13:01:28 +0000</pubDate>
		<dc:creator>meier</dc:creator>
				<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[join]]></category>
		<category><![CDATA[Joomla]]></category>
		<category><![CDATA[Sql]]></category>

		<guid isPermaLink="false">http://meier-online.com/?p=400</guid>
		<description><![CDATA[Ein kleiner Kniff für den Joomla Community Builder
Neulich erhielt ich eine kleine Auftragsanfrage. Ein bestehende Webanwendung wird stark erweitert und dabei auf das CMS &#8220;Joomla&#8221; umgestellt. Zur Mitgliederverwaltung wird die Erweiterung &#8220;Community Builder&#8221; eingesetzt.
Bisher hatten die Nutzer eine Nummer als Loginnamen. Diese Nummer soll jetzt für alle alten Nutzer in ein Feld &#8220;Mitgliedsnummer&#8221; überführt werden. [...]]]></description>
			<content:encoded><![CDATA[<h3>Ein kleiner Kniff für den Joomla Community Builder</h3>
<p>Neulich erhielt ich eine kleine Auftragsanfrage. Ein bestehende Webanwendung wird stark erweitert und dabei auf das CMS &#8220;Joomla&#8221; umgestellt. Zur Mitgliederverwaltung wird die Erweiterung &#8220;Community Builder&#8221; eingesetzt.<br />
Bisher hatten die Nutzer eine Nummer als Loginnamen. Diese Nummer soll jetzt für alle alten Nutzer in ein Feld &#8220;Mitgliedsnummer&#8221; überführt werden. So weit die Anforderung aus Kundensicht.</p>
<h3>Analyse</h3>
<p>Joomla verwaltet die Benutzer in einer Tabelle <em>jos_user</em>. <span id="more-400"></span>Der &#8220;Community Builder&#8221; ermöglicht es, zu einem Nutzerdatensatz weitere Felder hinzuzufügen. Die Felder landen in der gesonderten Tabelle <em>jos_profiler</em>. Mithilfe der ID sind diese beiden Datensätze verknüpft. Auf diese Weise muss der Community Builder keine Tabellen des Joomla-Kerns verändern. Allerdings ist das Hantieren mit zwei Tabellen natürlich programmtechnisch aufwendiger und fehleranfälliger.</p>
<p><img class="alignnone size-full wp-image-406" title="Grafische Darstellung des Problems: ein Feld soll aus einer verknüpften Tabelle kopiert werden" src="http://meier-online.com/blog/uploads/update-joined-table.png" alt="Grafische Darstellung des Problems: ein Feld soll aus einer verknüften Tabelle kopiert werden" width="380" height="200" /></p>
<p>Die Anforderung lautet demnach: Für alle<em> jos_user</em> Datensätze, die eine Zahl im Feld username haben, setze diese Zahl in das Feld Mitgliedsnummer des dazugehörigen Datensatzes in der Tabelle <em>jos_profiler</em>.</p>
<h3>Geht das mit SQL?</h3>
<p>Man kann das Problem sicherlich durch ein kleines PHP-Programm lösen. Wenn es mit einem SQL Befehl funktioniert, ist das viel einfacher. Ein Grund für mich, die Dokumentation zu MySQL genauer durchzusehen.</p>
<h3>Auswahl aller Zahlen</h3>
<p>Glücklicherweise unterstützt die verwendete MySQL Datenbank reguläre Ausdrucke. Alle usernamen, die nur aus Ziffern bestehen, lassen sich so abrufen:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> username <span style="color: #993333; font-weight: bold;">FROM</span> jos_users <span style="color: #993333; font-weight: bold;">WHERE</span> username <span style="color: #993333; font-weight: bold;">REGEXP</span> <span style="color: #ff0000;">'^[0-9]+$'</span></pre></div></div>

<h3>Verknüpfung beider Tabellen</h3>
<p>DieVerknüpfung zweier Datenbanktabellen wird auch als &#8220;join&#8221; bezeichnet, in unserem Fall ein &#8220;inner equijoin&#8221;.<br />
Um das Feld <em>username</em> und die Mitgliedsnummer gleichzeitig anzuzeigen, verwenden wir:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> jos_users<span style="color: #66cc66;">.</span>username<span style="color: #66cc66;">,</span> jos_comprofiler<span style="color: #66cc66;">.</span>cb_mitgliedsnummer
<span style="color: #993333; font-weight: bold;">FROM</span> jos_comprofiler<span style="color: #66cc66;">,</span> jos_users
<span style="color: #993333; font-weight: bold;">WHERE</span> jos_comprofiler<span style="color: #66cc66;">.</span>user_id <span style="color: #66cc66;">=</span> jos_users<span style="color: #66cc66;">.</span>id</pre></div></div>

<p>Diese Anweisung hilft auch bei der Kontrolle, ob am Ende alles richtig gesetzt ist.</p>
<h3>Setzen der Daten</h3>
<p>Als letzter Schritt bleibt noch, das Feld des einen Datensatzes mit dem Inhalt des Felds des korrespondierenden Datensatzes der anderen Tabelle zu setzen. Zum Glück funktionieren die beiden obigen Techniken auch im <em>UPDATE</em> Befehl von SQL.</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">UPDATE</span> jos_comprofiler<span style="color: #66cc66;">,</span> jos_users
<span style="color: #993333; font-weight: bold;">SET</span> jos_comprofiler<span style="color: #66cc66;">.</span>cb_mitgliedsnummer <span style="color: #66cc66;">=</span> jos_users<span style="color: #66cc66;">.</span>username
<span style="color: #993333; font-weight: bold;">WHERE</span> jos_comprofiler<span style="color: #66cc66;">.</span>user_id <span style="color: #66cc66;">=</span> jos_users<span style="color: #66cc66;">.</span>id
  <span style="color: #993333; font-weight: bold;">AND</span> jos_users<span style="color: #66cc66;">.</span>username <span style="color: #993333; font-weight: bold;">REGEXP</span> <span style="color: #ff0000;">'^[0-9]+$'</span></pre></div></div>

<p>Mit einem einzigen SQL-Befehl konnte das Kundenproblem gelöst werden. Möglich macht diese Magie der mathematische Unterbau von SQL, die relationale Algebra.</p>
]]></content:encoded>
			<wfw:commentRss>http://meier-online.com/2009/05/sql-update-join/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Mehrsprachige Webseiten mit Ruby on Rails</title>
		<link>http://meier-online.com/2009/04/localize-ruby-on-rails/</link>
		<comments>http://meier-online.com/2009/04/localize-ruby-on-rails/#comments</comments>
		<pubDate>Sat, 11 Apr 2009 21:09:44 +0000</pubDate>
		<dc:creator>meier</dc:creator>
				<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Mehrsprachigkeit]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Übersetzung]]></category>

		<guid isPermaLink="false">http://meier-online.com/?p=370</guid>
		<description><![CDATA[Teil 1 &#8211; Übersicht
Software in mehreren Sprachen anzubieten ist eine immer wiederkehrende Aufgabenstellung. Um so erstaunlicher ist es, dass Ruby on Rails erst sehr spät hierfür ein standardisiertes Vorgehen eingeführt hat. Seit Version 2.2. ist eine &#8220;Internationalization API&#8221; Bestandteil von Ruby on Rails.
Struktur des Frameworks
Das Framework besteht aus einen &#8220;öffentlichen&#8221; und einen &#8220;privaten&#8221; Teil. Das [...]]]></description>
			<content:encoded><![CDATA[<h3>Teil 1 &#8211; Übersicht</h3>
<p>Software in mehreren Sprachen anzubieten ist eine immer wiederkehrende Aufgabenstellung. Um so erstaunlicher ist es, dass Ruby on Rails erst sehr spät hierfür ein standardisiertes Vorgehen eingeführt hat. Seit Version 2.2. ist eine &#8220;Internationalization API&#8221; Bestandteil von Ruby on Rails.<img class="aligncenter size-full wp-image-374" title="Das Ruby-On-Rails Mehrsprachigkeitsmodul" src="http://meier-online.com/blog/uploads/rails-i18n.png" alt="Das Ruby-On-Rails Mehrsprachigkeitsmodul" width="480" height="300" /><span id="more-370"></span></p>
<h3>Struktur des Frameworks</h3>
<p>Das Framework besteht aus einen &#8220;öffentlichen&#8221; und einen &#8220;privaten&#8221; Teil. Das I18N Modul bildet den öffentlichen Teil mit den Methoden, die wir in unserem Quelltext aufrufen.</p>
<p>Das private Backend ist austauschbar. Die Standardversion liest die Texte aus Dateien in Yaml-Format oder aus normalen Rubydateien ein.</p>
<h3>Aufruf</h3>
<p>In unserem Quelltext ersetzen wir alle zu übersetzenden Texte durch Aufrufe der <em>I18N.translate()</em> Methode. Dank eines Alias können wir auch einfach t() schreiben. Als Parameter übergeben wir einen Schlüssel, mit dem das Backend die richtige Übersetzung nachschlägt.</p>
<p>Der Schlüssel kann einen String oder ein Symbol sein. Normalerweise ist ein Symbol als Hashkey ja geringfügig performanter. Da der Schlüssel bei der Verarbeitung in seine Bestandteile zerlegt wird, erwarte ich, dass dieser Vorteil verschwindet.</p>
<p>In einer typischen Webapplikation sind viele der zu übersetzenden Texte in den Views, also den .erb-Templates. Als Abkürzung für reinen HTML-Text gibt es folgenden Tag:</p>
<pre>&lt;%=t 'key' %&gt;</pre>
<h3 class="western">Organisation</h3>
<p>Die Symbole haben eine hierarchische Struktur. Als Organisation bietet sich an:</p>
<p>&#8220;controllername.viewname.key&#8221;, also zum Beispiel &#8216;companies.show.header&#8217;</p>
<h3>Die Sprachdateien</h3>
<p>Als Formate der Sprachdatei sind Ruby-Quelltext und Yaml vorgesehen. Die Übersetzung wird nun meistens von einer Person ohne Rubykenntnisse durchgeführt. Deshalb ist die Yaml-Datei zu empfehlen.</p>
<p>Das Format sieht so aus</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">de:
  users:
    show:
      header: &quot;Unternehmensdaten&quot;
      intro: &quot;Für dieses Unternehmen sind die folgenden Daten gespeichert:&quot;</pre></div></div>

<p style="margin-bottom: 0cm;">Die Sprache ist der erste Key, normalerweise sind dadurch die Texte der verschiedenen Sprachen räumlich getrennt. Um die Arbeit für die Übersetzer zu erleichtern, können mit einem &#8216;#&#8217; Zeichen Kommentare eingefügt werden. Und natürlich sollten die bezeichnenden Schlüsselwerte möglichst klar sein. Aber selbst dann sind die YAML-Dateien nicht optimal, wenn Entwickler und Übersetzer nicht dieselbe Person ist.</p>
<p><a href="/2009/05/localize-ruby-on-rails-p2/">Zu Teil 2 dieses Artikels</a></p>
]]></content:encoded>
			<wfw:commentRss>http://meier-online.com/2009/04/localize-ruby-on-rails/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
