December 15th, 2007 at 5:26 pm

Count over two SQL tables

A bit of SQL that saved my butt lately: Have you ever needed to relate a value from one table to the count of another value in another table? Given you have two tables, one for a timetable, the other for tickets, and you want to find out how many tickets are sold for each tour in the timetable, the following will give it to you (tours.tour_id is related to tickets.ticket_tour_id, who'd have thought of that):

MySQL:
  1. SELECT DISTINCT tour_id, COUNT(ticket_tour_id)
  2. FROM tours
  3. RIGHT JOIN tickets
  4. ON tour_id = ticket_tour_id
  5. GROUP BY ticket_tour_id
  6. ORDER BY departure;

December 12th, 2007 at 12:47 pm

Playing with xgettext

xgettext is a great shell tool to create po files (i.e. Gettext translation templates). It is also able to merge existing translations with new strings. For example, to create a po template from all PHP files in a directory tree and preserve already done translations from the file my_translation-de_DE.po, enter:

CODE:
  1. mv my_translation-de_DE.po messages.po
  2. find . -type f -iname "*.php" | xgettext --keyword=__ --keyword=_e -j -f -
  3. mv messages.po my_translation-de_DE.po

Now you have a new my_translation-de_DE.po, with all the translated and the newly added strings appended to this file. (The --keywords parameter is very useful to specify your translation function(s), because if you do so, xgettext will not extract all the other strings, too.)

Unfortunately, xgettext is not able to expunge strings that are no longer existing. This behaviour is easy to explain: In many cases, you might be doing an incremental update of your translation template (i.e. you only add the strings for a subset of your files). If xgettext would expunge the translations for which no sting wasn't found in your code, you would always have to recreate the po template completely. Anyway, a little option to expunge translations that weren't found in the original, would be nice.

A little trick will at least help to determine the strings that do no longer exist: Open the po file to be merged and delete all #: lines (the regex ^#:.*$ will match them). Then merge the files as usual. In the new file, all messages without a #: marker do no longer exist. You can even modify the above code to do so automatically:

CODE:
  1. grep -v "^#:" my_translation-de_DE.po> messages.po
  2. find . -type f -iname "*.php" | xgettext --keyword=__ --keyword=_e -j -f -
  3. mv messages.po my_translation-de_DE.po

This way, you will preserve your translations, but your references are recreated, and you can easily see which strings do not exist anymore.

Update, 16.04.08: When I wrote this post, I didn't know about the msgmerge tool. Using it is much better than the grep foo above. Use it as follows:

CODE:
  1. echo ''> messages.po # xgettext needs that file, and we need it empty
  2. find . -type f -iname "*.php" | xgettext --keyword=__ --keyword=_e -j -f -
  3. msgmerge -N existing.po messages.po> new.po
  4. mv new.po existing.po
  5. rm messages.po

It looks a bit more complex, but it's the best generic solution I can provide. Note the -N parameter for msgmerge: It suppresses the fuzzy mode, which yields more confusion and extra work than anything else.

December 11th, 2007 at 7:17 am

Calculating the V.A.T. amount from the total price

Sometimes you need to calculate the V.A.T. (for Germans: MwSt.) from a given total price. This is, for example, if you charge an arbitrary total price, but need to display the V.A.T. percentage along with the V.A.T. amount. For this purpose, you can use the following code:

PHP:
  1. <?php
  2.    
  3.     function calc_vat_amount_from_total($total, $vat)
  4.     {
  5.         $total = (float)$total;
  6.         $vat = (float)$vat;
  7.  
  8.         if (!$total || !$vat) return false;
  9.  
  10.         $net = $total / (float)('1.'.$vat);
  11.         $vatAmount = $total - $net;
  12.  
  13.         return sprintf("%01.2f", $vatAmount);
  14.     }
  15.  
  16.     $total = '35.00'; // It's a string, but could also be a float or int.
  17.     $vat = '19'; // dito
  18.  
  19.     $vat_amount = calc_vat_amount_from_total($total, $vat);
  20.     echo "The ticket fare of $total &#8364; contains $vat% V.A.T. ($vat_amount &#8364;).";
  21.  
  22. ?>

December 10th, 2007 at 11:36 pm

Hello world!

Hello World indeed! This is my new little notepad for code snippets and ideas. I'll post stuff on an irregular basis, just as I feel like it. Maybe somebody finds the chunks posted here useful. If so, take them, use them, have fun. For all code and other stuff found on this website, the "No problem, Bugroff" license applies (although I don't agree with the GPL bashing in the license text), unless explicitely noted otherwise. Attribution is apprechiated, though not neccessary.