can you get more random?

debugging ansible

March 14th, 2016 Posted in geeky stuff | No Comments »

I’ve been playing with Ansible recently, and enjoying automating my server installs, after years of relying on home-made scripts (or worse).

From time to time I need to find out why Ansible isn’t doing what I think it should be, and after using -vvvv verbose flag, my next step is running the generated ansible installation script manually on the server. I didn’t find this explained anywhere, so I’m documenting it here for future reference. Read the rest of this entry »

Share

Email productivity with Spark and ActiveInbox

February 26th, 2016 Posted in geeky stuff | No Comments »

I recently discovered Spark, and now use it along with ActiveInbox to effectively fight my way through the hundreds of emails I receive every day. If you haven’t tried either of these tools, I can recommend both of them.

ActiveInbox uses GMail’s labels to convert your inbox into a GTD-style task manager, allowing you to quickly go through emails in your inbox, classifying them as Actions to do, or postponing them until a future date (amongst other actions). It means you don’t need to treat your inbox as a todo list, with emails backing up until you no longer have a clear view of awaiting tasks. Instead you can clearly see overdue actions and add tasks and events to your calendar.

I discovered Spark with the release of version 2.0 of their app. Spark is an iOS email app that makes burning through your emails easy. Tasks like tagging, deleting, forwarding and archiving mails can be easily achieved by swiping directly on the mail, making it easy to treat emails rapidly.

Unfortunately there is a compatibility problem with these tools – in their default state it isn’t possible to use them together.  Read the rest of this entry »

Share

CAPE value 2014 returns

January 3rd, 2015 Posted in Uncategorized | No Comments »

Meb Faber’s CAPE value model returned 21% in 2013 but seemingly didn’t do so well in 2014. However that’s only the case if you’re looking at your returns in USD. converting the start and end of year values to euros and local currency, the return is around zero.  You can see my CAPE 2014 data in Google sheets. OK, so an average return of 0% is nothing to write home about, but it’s not quite as bleak as -13%. The next question is how easy it would be to hedge the currency risk. Any ideas? Also it would be interesting to see what the 2013 returns were in local currency. Maybe that’s a project for tomorrow.

Share

Better l10n for Joomla

July 6th, 2014 Posted in geeky stuff, languages | No Comments »

For the past couple of weeks I’ve been working on a site developed in Joomla. This wasn’t by choice, but it was a good chance to learn more about the CMS. The site is available in three languages so the question of content translation quickly came up.

There are several Joomla Plugins for managing multi-lingual content available, but none of them fit our needs.

The current available plugins can be broadly classified in 2 groups Read the rest of this entry »

Share

Learning portuguese : Day 1 – Pronunciation

September 4th, 2013 Posted in languages, portuguese | No Comments »

There are many different language learning strategies, but the one thing you’ll hear again and again is the importance of immersing yourself in the language. Obviously the best way to do this is to live in the country where your language is spoken, but if that’s not possible, listening to podcasts is the next best thing, as it will help you recognise the sound of the language and start to learn the pronunciation. Whilst learning German, I listened to Read the rest of this entry »

Share

September Challenge : Learn Portuguese

September 3rd, 2013 Posted in languages, portuguese | No Comments »

I’m going to be spending a long weekend in Lisbon in October and thought it would be interesting to see how much Portuguese I can learn in the next few weeks. I’ve been to Portugal several times before and each time I regret not being able to converse with the locals. After 2 weeks in the Azores a few years ago I managed to communicate using Spanish with (what was probably a rather bad approximation to a) Portuguese accent along with a few basic Portuguese words thrown in, but the result wasn’t pretty, although it got me a few smiles along the way.

Ok, so I’m not planning on becoming fluent in 5 weeks (well it would be nice, if a little unrealistic…). The idea is to try out various language learning sites, tools and methods and see what works for me. I’ll be spending an hour a day (if I can motivate myself) and reporting back here on my progress.

My first step was changing the language on my phone, which is always amusing. My phone has been in German for a while now, but I get the impression that I already understand more in Portuguese than I did with a German iPhone, after 2 years of learning German. Next step, basic vocabulary. I think I’ll start with DuoLingo, as I love their ‘Gamification’ of language learning.

40 hours to go…

Share

10 000 sentences, the easy way

June 7th, 2013 Posted in geeky stuff, languages | No Comments »

Apart from spending copious amounts of time learning Spanish German, I’ve also been researching the most effective methods for language learning. Meta-language learning, I guess.

My first discovery was Read the rest of this entry »

Share

Symfony i18n : dumping and loading translation strings

September 13th, 2012 Posted in geeky stuff | No Comments »

I’ve been meaning to write about this for literally years, but never got round to it. Hopefully this will be useful to someone. After an only partially sucessful attempt to manage symfony i18n strings in a MySQL DB, I finally gave up and reverted back to the default XLIFF file method. One of the reasons for initially wanting to store the translations in a DB was to build an easy to use interface to allow translators to easily find untranslated strings. Unfortunatley this didn’t work as well as I was hoping, and the alternatives (installing pootle, or getting translators to install and learn how to use an xliff tool) werent’ much better.

I finally decided that the easiest way to update translations would be by dumping untranslated strings to a file before sending them to a translator. Unfortunately I couldn’t find a way to easily dump strings to a file and reload translated strings, so I wrote a couple of new tasks to do this for me.

You need to create the following two files: lib/tasks/sfI18nDumpTask.class.php


<?php
/*
* Current known limitations:
* - Can only works with the default "messages" catalogue
* - For file backends (XLIFF and gettext), it only saves/deletes strings in the "most global" file
*/

/**
* Dumps i18n strings from messages.xml files.
*
*/
class sfI18nDumpTask extends sfBaseTask
{
/**
* @see sfTask
*/
protected function configure()
{
$this->addArguments(array(
new sfCommandArgument('application', sfCommandArgument::REQUIRED, 'The application name'),
new sfCommandArgument('culture', sfCommandArgument::REQUIRED, 'The target culture'),
));

$this->addOptions(array(
new sfCommandOption('untranslated', null, sfCommandOption::PARAMETER_NONE, 'Output all new found strings'),
));

$this->namespace = 'i18n';
$this->name = 'dump';
$this->briefDescription = 'dumps i18n strings from messages.xml files';

$this->detailedDescription = <<<EOF
The [i18n:dump|INFO] task extracts i18n strings from your project files
for the given application and target culture:

[./symfony i18n:dump frontend fr|INFO]

By default, the task dumps all translations it found in the current project.

[./symfony i18n:dump frontend fr|INFO]

If you want to dump the untranslated strings, use the [--untranslated|COMMENT] option:

[./symfony i18n:dump --untranslated frontend fr|INFO]

EOF;
}

public function execute($arguments = array(), $options = array())
{
$this->logSection('i18n', sprintf('dumping i18n strings for the "%s" application', $arguments['application']));

// get i18n configuration from factories.yml
$config = sfFactoryConfigHandler::getConfiguration($this->configuration->getConfigPaths('config/factories.yml'));

$class = $config['i18n']['class'];
$params = $config['i18n']['param'];
unset($params['cache']);

$i18n = new $class($this->configuration, new sfNoCache(), $params);
$i18n->getMessageSource()->setCulture($arguments['culture']);
$i18n->getMessageSource()->load();

$messages = $i18n->getMessageSource()->read();

$count=0;
foreach ($messages as $catalogue => $translations) {
$this->logSection('i18n', sprintf('found "%d" i18n strings', count($translations)));
foreach ($translations as $key => $values) {
if ($options['untranslated'] && ('' != $values[0])) {
continue;
}
$count++;
$source = str_replace('"', '""', $key);
$translation = str_replace('"', '""', $values[0]);
print "$values[1]|\"$arguments[culture]\"|\"$source\"|\"$translation\"\n";
}
}

$this->logSection('i18n', sprintf('dumped "%d" i18n strings', $count));

}
}

and lib/task/sfI18nLoadTask.class.php


<?php

/*
* Current known limitations:
* - Can only works with the default "messages" catalogue
* - For file backends (XLIFF and gettext), it only saves/deletes strings in the "most global" file
*/

/**
* loads i18n strings from php files.
*
*/
class sfI18nLoadTask extends sfBaseTask
{
/**
* @see sfTask
*/
protected function configure()
{
$this->addArguments(array(
new sfCommandArgument('application', sfCommandArgument::REQUIRED, 'The application name'),
new sfCommandArgument('culture', sfCommandArgument::REQUIRED, 'The target culture'),
new sfCommandArgument('filename', sfCommandArgument::REQUIRED, 'The translation csv file'),
));

$this->addOptions(array(
new sfCommandOption('no-overwrite', null, sfCommandOption::PARAMETER_NONE, 'Dont overwrite existing translations'),
));

$this->namespace = 'i18n';
$this->name = 'load';
$this->briefDescription = 'loads i18n strings from php files';

$this->detailedDescription = <<<EOF
The [i18n:load|INFO] task loads i18n strings from your project files
for the given application and target culture:

[./symfony i18n:load frontend fr filename|INFO]

By default, the task will load all strings from the file
into the current project.

If you only want to load previously untranslated strings, use the [--no-overwrite|COMMENT] option:

[./symfony i18n:load --no-overwrite frontend fr filename|INFO]

EOF;
}

/**
* @see sfTask
*/
public function execute($arguments = array(), $options = array())
{
$this->logSection('i18n', sprintf('loading i18n strings for the "%s" application', $arguments['application']));

// get i18n configuration from factories.yml
$config = sfFactoryConfigHandler::getConfiguration($this->configuration->getConfigPaths('config/factories.yml'));

$class = $config['i18n']['class'];
$params = $config['i18n']['param'];
unset($params['cache']);

$i18n = new $class($this->configuration, new sfNoCache(), $params);
$i18n->getMessageSource()->setCulture($arguments['culture']);
$i18n->getMessageSource()->load();

$messageSource = $i18n->getMessageSource();
$messages = $messageSource->read();

if ($loaded_list = file($arguments['filename'])) {
foreach ($loaded_list as $line) {
$line = chop($line);
if (preg_match('/(\d+)\|"(.*)"\|"(.*)"\|"(.*)"/', $line, $matches)) {
list($id, $culture, $source, $translation) = array($matches[1], $matches[2], $matches[3], $matches[4]);
if ($culture == $arguments['culture']) {
$messageSource->update($source, $translation, '');
}
}
}
} else {
$this->logSection('i18n', sprintf('Cant open file "%s"', $arguments['filename']));
}

if ($options['no-overwrite'])
{
$this->logSection('i18n', 'saving only new i18n strings');
} else {
}
$messageSource->save();

}
}

Before dumping the new strings to a file, you should first add any new untranslated strings using the builtin symfony i18n:extract command:

 ./symfony i18n:extract --auto-save --display-new frontend <culture> 

Then you’re ready to dump the new untranslated strings to a file :

 ./symfony i18n:dump frontend <culture> --untranslated > untranslated.csv 

You can then import this file into your favourite spreadsheet program. In NeoOffice this is done by opening a fresh spreadsheet and importing the data via “Insert” > “Sheet from external file” and making sure to add pipe ‘|’ as field seperator. YMMV in your spreadsheet tool of choice. Once the translations have been added in the 4th column of the spreadsheet, save the document as a pipe separated csv file before using the following command to reload the translated strings:

 ./symfony i18n:dump frontend <culture> translated.csv 
Share

Word of the day : Hyperpolyglotist

April 12th, 2012 Posted in german, languages | No Comments »

Talking about language learning, as I was, I found an article on the BBC website about hyperpolyglotism. I was pretty happy with my acceptable french, moderate spanish and fairly miserable german until I saw that video.

Share

Learning German with Anki

April 12th, 2012 Posted in german, languages | 6 Comments »

I’ve been told by several people that German is an easy foreign language for English speakers to learn. My experience in the past few months leads me to believe otherwise. I always thought that German was a logical language where it was enough to follow the rules. Well that may be true, but there are hundreds of rules and as many exceptions.

Despite this, I haven’t been put off, and fairly early on I discovered Anki which is an incredible tool to help with learning vocabulary (Apparently this kind or tool is called an SRS or Spaced repetition system. Flashcards to you and I). Vocab learning was never my strong point, but Anki really helps. Whether I have 10 minutes on the U-Bahn or an hour in the evening, I can quickly assimilate a few dozen more words.

However the dearth of dictionary files was an initial problem, so I have created a beginners file from various sources, which may be of use to any other beginning German learners. Check out my English-German Anki deck. I’ve been adding to this file for the past few months, and I hope it is as error-free as possible, but if you do find any errors, please let me know and I’ll correct them.

I’ve also uploaded the file to Google docs, if anyone wants write access to modify/improve the data, let me know. I’ll update the anki file with the latest greatest version.

Share