The best way to deal with translations

465 views
Skip to first unread message

Brian King

unread,
Nov 16, 2011, 5:19:21 AM11/16/11
to symfony-...@googlegroups.com
Hi,

David Buchmann, Daniel Barsotti and myself discussed the best approach
to implementing translations in the CMF. Please take a few moments to
read about our discussion and tell us what *you* think. Lacking any
input, we'll likely start on implementation of PHPCR-ODM-level
translation support.

At the moment, the MultilangContentBundle can be used. We don't feel
that it makes sense to have the translations done by this CMF-specific
Bundle though. After all, translations are something you want to use
outside of a CMF, too.

We have considered a few ways to rework this to be more general, and,
hopefully, thus have more community support. The Gedmo
DoctrineExtensions already exist, with a couple of translation
extensions. Another idea would be to add support for translation at
the PHPCR-ODM level.

We considered:
1. Adding PHPCR-ODM support for the Gedmo Translator extension [1]
2. Adding PHPCR-ODM support for the Gedmo Translatable extension [2]
3. Adding native translation support to PHPCR-ODM [3]

Option 1. was favored by no one. The Translator extension is very
explicit and does not use annotations. This probably makes it easier
to trace through at runtime and understand what is happening, but it
also requires a lot of configuration at development time, which seems
not so nice. We could implement the Gedmo-style translate() method,
but we'd share just about no code with the rest.

Option 2. could be done, but would require a fair amount of work to do
reasonably well. The existing implementations for ORM and MongoDB
store each translated field in a separate Entity/Document; this would
be inefficient for Jackrabbit. The implementation might end up being
a bit twisted if it is to be fairly efficient and comply with the
interfaces.

Option 3. is what we are leaning towards. It seems like it would be
the most straightforward for implementation and usage. It would
definitely be the most efficient.

The usage of the PHPCR-ODM-level translations is envisaged something like this:

$article = new Article();
$article->setTitle('New song');
$odm->persist($article); // persist default (configured) translation
$article->setTitle('Neues Lied');
$odm->persistTranslation($article, 'de');
...
$article = $odm->findTranslation('/path/to/article', 'de');
$article->setTitle('Nouvelle chanson');
$odm->persistTranslation($article, 'fr');
...

The translatable fields could be annotated like this:
@PHPCRODM\String(translatable=true)


The pros and cons that we thought about for PHPCR-ODM-level translations:
pros:
* easy to use
* no additional bundle
* explicit API (e.g. persistTranslation(), not $article->lang='de';
persist($article))
* easy to implement
* efficient
* nice feature for an ODM
cons:
* monolithic
* less compatible with other doctrine doc managers. would make
migration phpcr-odm => foo-oxm harder.
* adds yet another way to translate something
* may complicate implementation of OxM-agnostic Bundles/libs

Most of the cons be could be overcome at some future time by
implementing something that works with the currently-most-accepted way
of doing translations in the Doctrine world.

Whatcha think?

[1] https://github.com/l3pp4rd/DoctrineExtensions/pull/176
[2] https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/translatable.md
[3] https://github.com/doctrine/phpcr-odm

Fabrice Bernhard

unread,
Nov 16, 2011, 5:35:34 AM11/16/11
to symfony-...@googlegroups.com
Hi Brian,

I just come out of a meeting where we were discussing i18n strategy for RogerCMS. Since we need it quickly on the database level we will most certainly use the Translatable extension.

In my opinion solution 3 is the good way to go. The API you suggest is quite nice by the way.

Would it be possible to also implement in parallel the now generally accepted "$article->setTranslatableLocale('de_de');$odm->persist($article);" API ? For compatibility reasons ?

Fabrice

David Buchmann

unread,
Nov 16, 2011, 7:13:03 AM11/16/11
to symfony-...@googlegroups.com, Fabrice Bernhard
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

hi fabrice,

> I just come out of a meeting where we were discussing i18n strategy for
> RogerCMS. Since we need it quickly on the database level we will most
> certainly use the Translatable extension.

interesting. reminds me i have to check out RogerCMS asap.
note that the translatable extension won't work with phpcr-odm at the
moment as there is no binding. although to do it in a "stupid" (aka not
performant) way should be rather simple.

> In my opinion solution 3 is the good way to go. The API you suggest is
> quite nice by the way.
>
> Would it be possible to also implement in parallel the now generally
> accepted
> "$article->setTranslatableLocale('de_de');$odm->persist($article);" API
> ? For compatibility reasons ?

we discussed keeping a @locale annotation for the document, at least for
reading purposes. we could for sure define that if the document has an
@locale annotation field that is non-empty, we use that instead of the
default configured language.
the reason we wanted the persistTranslation is because we feel its very
implicit logic changing the locale field and then re-persisting the
document. but i guess it won't hurt to offer both ways.

> $article = $odm->findTranslation('/path/to/article', 'de');

what we really did not like about the translatable extension was the way
to load the non-default translation by first finding the document, then
changing the locale and doing the refresh. it requires additional round
trips and is just weird. also, we do not like to force the system to
have a main locale and optional translations. we want to be able to have
one document in french and the other in english and fall back in both
directions.

> $article->setTitle('Nouvelle chanson');
> $odm->persistTranslation($article, 'fr');
> ...
>
> The translatable fields could be annotated like this:
> @PHPCRODM\String(translatable=true)

the cool thing here is that this works for any type of field (like
binary, so you could store a locale specific image)

cheers,david

- --
Liip AG // Agile Web Development // T +41 26 422 25 11
CH-1700 Fribourg // PGP 0xA581808B // www.liip.ch
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk7DqMsACgkQqBnXnqWBgItngACeP1yaUXAnezq6mBo/nhFbGrJX
UwoAn2WxqdU3QaLXACDZ3dpXx1frKea4
=D08w
-----END PGP SIGNATURE-----

Uwe Jäger

unread,
Nov 16, 2011, 8:02:00 AM11/16/11
to symfony-...@googlegroups.com
Hi,

I like the idea of the extra attribute for the annotation, but I'm not
sure whether the suggested API is what is needed. When showing content
to an "end user" we need the version in the language selected by the
user. It's hard to write different code (find vs. findTranslation)
depending on some properties being translatable or not. What would
find return for your example?

On the other hand it is common to edit translations in a backend for
several languages, so I guess it would be useful to have the
possibility to retrieve and store translatable properties as an array
with the different translations, something like
$article->setTitle(array('de' => 'Neues Lied', 'fr' => 'Nouvelle
chanson'));

Having the latter (the translated property in an array) resolving the
current language could be delegated to some other layer like forms or
templates.

I don't have a quick solution for that now. But maybe somebody else
has an idea to address this.

Cheers
Uwe

2011/11/16 Brian King <br...@liip.ch>:

David Buchmann

unread,
Nov 16, 2011, 8:28:41 AM11/16/11
to symfony-...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

hi uwe,

> I like the idea of the extra attribute for the annotation, but I'm not
> sure whether the suggested API is what is needed. When showing content
> to an "end user" we need the version in the language selected by the
> user. It's hard to write different code (find vs. findTranslation)
> depending on some properties being translatable or not. What would
> find return for your example?

the idea of this is: we inject a default language selection strategy
(including fallback) into phpcr-odm. this can be as simple as a
configured default language, or the session locale or some per-user
preferences. if you do find, you just get the best match.

what i do like about this approach is that in find, you just don't care
if the document is multilang or not. the phpcr-odm language fallback
strategy will just make sure you get the best thing.

the findTranslation is only used when you need to explicitly get a
translation of a document (mostly in the translation workflow).

> On the other hand it is common to edit translations in a backend for
> several languages, so I guess it would be useful to have the
> possibility to retrieve and store translatable properties as an array
> with the different translations, something like
> $article->setTitle(array('de' => 'Neues Lied', 'fr' => 'Nouvelle
> chanson'));

hm, this would indeed be a nice feature to be able to set multiple
translations at once. not sure how we could do it though.
in the current multilang bundle, we have 2 ways to store translations:
as additional namespaced attributes of the node, or as child nodes in a
language namespace. additionally we could add translations into their
own tree, but the drawback of that is that some application code needs
to keep track of them, whereas the children just are moved/deleted with
the main node.

initially we also thought about multivalue properties for translations.
but unfortunately phpcr multivalue properties are just arrays, not
hashmaps (you can't have an arbitrary key like "de").

as we propose it, you would update your document and persist the
translations per translation instead of per field. the difference is
mainly in how you express it in code, not fundamental.

> Having the latter (the translated property in an array) resolving the
> current language could be delegated to some other layer like forms or
> templates.

(see above: we would delegate it into phcpr-odm). i think its best
handled inside the odm. with the additional explicit methods, the form
handling can store translations.

> I don't have a quick solution for that now.

raising questions is appreciated as well :-)

cheers,david
- --
Liip AG // Agile Web Development // T +41 26 422 25 11
CH-1700 Fribourg // PGP 0xA581808B // www.liip.ch
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk7DuokACgkQqBnXnqWBgIuXWwCffLvJlOHRZX+NA3o6KPoJyZQ3
fJoAn16KSz8WgX9F6398iCCIbXRirfQN
=H988
-----END PGP SIGNATURE-----

Uwe Jäger

unread,
Nov 16, 2011, 9:38:26 AM11/16/11
to symfony-...@googlegroups.com
Hi David,

> the idea of this is: we inject a default language selection strategy
> (including fallback) into phpcr-odm. this can be as simple as a
> configured default language, or the session locale or some per-user
> preferences. if you do find, you just get the best match.
>
> what i do like about this approach is that in find, you just don't care
> if the document is multilang or not. the phpcr-odm language fallback
> strategy will just make sure you get the best thing.

Ok, that make sense. What when I store/persist the document later?

>> On the other hand it is common to edit translations in a backend for
>> several languages, so I guess it would be useful to have the
>> possibility to retrieve and store translatable properties as an array
>> with the different translations, something like
>> $article->setTitle(array('de' => 'Neues Lied', 'fr' => 'Nouvelle
>> chanson'));
>
> hm, this would indeed be a nice feature to be able to set multiple
> translations at once. not sure how we could do it though.
> in the current multilang bundle, we have 2 ways to store translations:
> as additional namespaced attributes of the node, or as child nodes in a
> language namespace. additionally we could add translations into their
> own tree, but the drawback of that is that some application code needs
> to keep track of them, whereas the children just are moved/deleted with
> the main node.

Well I'm just talking about an API, not how to store it. I just think
of some other software's frontend that displays some icon next to
translatable fields in the backend, allows to edit the current
language's value in the field and opens a table with all languages
when you click the icon. Basically it is more about translating the
entity (which is close to your proposed API) against translating a
property. But if we talk about content it might be translating
entities anyway.

I think the proposed API will result in some backend where you see the
complete entity and then change the language and again see the
complete entity with the translatable fields changed. It will be
rather hard to implement what I described above.

Cheers
Uwe

David Buchmann

unread,
Nov 16, 2011, 10:22:17 AM11/16/11
to symfony-...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

>> the idea of this is: we inject a default language selection strategy


>> (including fallback) into phpcr-odm. this can be as simple as a
>> configured default language, or the session locale or some per-user
>> preferences. if you do find, you just get the best match.
>>
>> what i do like about this approach is that in find, you just don't care
>> if the document is multilang or not. the phpcr-odm language fallback
>> strategy will just make sure you get the best thing.
>
> Ok, that make sense. What when I store/persist the document later?

hah. that just convinced me that we should support the locale annotation
and use that in save operations unless the explicit persistTranslation
is used :-)
good point, thank you uwe.

i think translating field oriented makes sense for system messages
translation (what is usually done with the xliff files).
translating content should be document oriented imho, it makes no sense
to just translate titles of documents for example. the issue i see is
that we need to load the document several times if we want to show all
languages in the backend interface, and cache the content in between,
because findTranslation will need to update the original document.
(otherwise if there could be more than one object for the same content,
we would risk weird effects when non-translated fields are changed and
persisted)
this indeed is not perfect. i am open to suggestions but have no great
idea atm.

we will need for sure some helper method to know what translations are
available of a specific document.
a list of all allowed locales is probably out of scope, as phpcr-odm
does not necesarily need to restrict them.

cheers,david
- --
Liip AG // Agile Web Development // T +41 26 422 25 11
CH-1700 Fribourg // PGP 0xA581808B // www.liip.ch
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk7D1SUACgkQqBnXnqWBgIumkgCdFUUeJt7ahf39ufRWwmU5jHm3
5XUAoKeAEd1pv7t1j5ALlrkeDc4Lkn8d
=Zmbd
-----END PGP SIGNATURE-----

Hari K T

unread,
Nov 16, 2011, 10:22:53 AM11/16/11
to symfony-...@googlegroups.com
Hi guys, 

You may be already thought of this .

But I have some doubts, not sure whether this topic is off to the particular subject . If so some one can change the subject . 

I was working with a website , and the SEO guy needs to add canonical link , nofollow , noindex , geo properties like latitude , longitude , region etc .

Is it happening at routing or , do we want to add on the creation ?

For eg ; Lets think there is no translation for an article .

example.com/en/about is only available .

Assume the user has choosen french and browsing about , the french page is not there , so how will the fallback happen ?

Show the fr/about with english content or will it route to en/about ?

Thank you for your time .

Hari K T
M: +91-9388758821 | W: http://harikt.com/blog

Fabrice Bernhard

unread,
Nov 16, 2011, 10:35:08 AM11/16/11
to symfony-...@googlegroups.com
On Wed, Nov 16, 2011 at 4:22 PM, Hari K T <ktha...@gmail.com> wrote:
Hi guys, 

You may be already thought of this .

But I have some doubts, not sure whether this topic is off to the particular subject . If so some one can change the subject . 

I was working with a website , and the SEO guy needs to add canonical link , nofollow , noindex , geo properties like latitude , longitude , region etc .

Is it happening at routing or , do we want to add on the creation ?

For eg ; Lets think there is no translation for an article .

example.com/en/about is only available .

Assume the user has choosen french and browsing about , the french page is not there , so how will the fallback happen ?

Show the fr/about with english content or will it route to en/about ?

I would do a redirect 302 to en/about. Depending on the CMS, it could be done in the routing or in the controller. But that means there must some API when the ODM does a silent fallback that tells you "silent fallback to some other language".

Fabrice

Uwe Jäger

unread,
Nov 17, 2011, 3:49:36 AM11/17/11
to symfony-...@googlegroups.com
Hi,

there is one more thing that comes into my mind: how do you want to
handle the traversal of the hierarchy with references, parent or child
annotation? If you retrieve the "default" translation how can I access
any other translation of a child? Would it make more sense just to
make this more explicit or leave it up to the content model? Say have
a node/document Page with children for content in different languages?

Cheers
Uwe

2011/11/16 Fabrice Bernhard <fabr...@theodo.fr>:

Lukas Kahwe Smith

unread,
Nov 17, 2011, 4:59:44 AM11/17/11
to symfony-...@googlegroups.com

On Nov 16, 2011, at 14:28 , David Buchmann wrote:

> initially we also thought about multivalue properties for translations.
> but unfortunately phpcr multivalue properties are just arrays, not
> hashmaps (you can't have an arbitrary key like "de").


well we could always emulate hashmaps with two multivalued fields. but the issue is that then we would have a problem translating multivalued fields.

regards,
Lukas Kahwe Smith
sm...@pooteeweet.org

Lukas Kahwe Smith

unread,
Nov 17, 2011, 5:03:23 AM11/17/11
to symfony-...@googlegroups.com

On Nov 16, 2011, at 14:28 , David Buchmann wrote:

>> On the other hand it is common to edit translations in a backend for
>> several languages, so I guess it would be useful to have the
>> possibility to retrieve and store translatable properties as an array
>> with the different translations, something like
>> $article->setTitle(array('de' => 'Neues Lied', 'fr' => 'Nouvelle
>> chanson'));
>
> hm, this would indeed be a nice feature to be able to set multiple
> translations at once. not sure how we could do it though.
> in the current multilang bundle, we have 2 ways to store translations:
> as additional namespaced attributes of the node, or as child nodes in a
> language namespace. additionally we could add translations into their
> own tree, but the drawback of that is that some application code needs
> to keep track of them, whereas the children just are moved/deleted with
> the main node.
>
> initially we also thought about multivalue properties for translations.
> but unfortunately phpcr multivalue properties are just arrays, not
> hashmaps (you can't have an arbitrary key like "de").
>
> as we propose it, you would update your document and persist the
> translations per translation instead of per field. the difference is
> mainly in how you express it in code, not fundamental.


the API that Uwe mentioned does indeed seem nice for and admin tool, however its going to be a bit confusing if you just want to set a single language. as such i would prefer we think about a helper class which can be given a class metadata and then do some magic via __call() to set values for different translations. if that ends up being less efficient, then i dont think this is a big concern as setting multiple translations like this isnt something you are going to be doing alot.

Lukas Kahwe Smith

unread,
Nov 17, 2011, 5:08:44 AM11/17/11
to symfony-...@googlegroups.com

On Nov 16, 2011, at 16:35 , Fabrice Bernhard wrote:

> On Wed, Nov 16, 2011 at 4:22 PM, Hari K T <ktha...@gmail.com> wrote:
> Hi guys,
>
> You may be already thought of this .
>
> But I have some doubts, not sure whether this topic is off to the particular subject . If so some one can change the subject .
>
> I was working with a website , and the SEO guy needs to add canonical link , nofollow , noindex , geo properties like latitude , longitude , region etc .
>
> Is it happening at routing or , do we want to add on the creation ?
>
> For eg ; Lets think there is no translation for an article .
>
> example.com/en/about is only available .
>
> Assume the user has choosen french and browsing about , the french page is not there , so how will the fallback happen ?
>
> Show the fr/about with english content or will it route to en/about ?
>
> I would do a redirect 302 to en/about. Depending on the CMS, it could be done in the routing or in the controller. But that means there must some API when the ODM does a silent fallback that tells you "silent fallback to some other language".

the concept we have for routing is that we have one node tree for defining the urls and another one for defining the content and you reference from the url node tree to the content tree. this also gives you the opportunity to add metadata about fallback rules etc in the url node tree.

that being said for translations we will likely have two approaches:
1) consider each language as a separate site with its own url tree. this will give a lot of manual control, most importantly allowing for totally different structures for each of the languages
2) have a single url tree for all/some languages and then define the fallback rules (which could also include disabling a node for a specific language). this is easier to maintain, but gives you less control

that being said .. it should also be possible to assemble a url tree from "subtrees" aka you can then mix and match approach 1) and 2)

David Buchmann

unread,
Nov 17, 2011, 8:25:51 AM11/17/11
to symfony-...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

hi,

thanks for this good discussion. i summarized the outcomes so far into
the wiki:
https://github.com/symfony-cmf/symfony-cmf/wiki/MultilangContentBundle

if there is no serious doubt, we will start implementing this tomorrow.

there are a few TODO for open points from the discussion, but i think we
don't need to solve all of them.

cheers,david

- --

Liip AG // Agile Web Development // T +41 26 422 25 11
CH-1700 Fribourg // PGP 0xA581808B // www.liip.ch
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk7FC18ACgkQqBnXnqWBgIvDTQCbBKdvNwssikDnENKWTLPKwR+w
vXgAoIKebflZRU17vtw9HdX4skGIcmQz
=ZEXV
-----END PGP SIGNATURE-----

David Buchmann

unread,
Nov 25, 2011, 3:05:26 AM11/25/11
to symfony-...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

hi,

we have most of the things implemented, but the traversal is giving me a
real headache.
the basic problem is: a translated document is *one* document. so if you
find it in a different language, the original document is modified. (if
we would not do that, we would get several copies of the same document
which is even worse)

at first we thought storing the requested language in the proxies and
load the documents in that language. this sounds good until you start
some use cases:

//default language is english

$parent = $dm->find('/parent'); //parent is english
$child = $dm->findTranslation('/parent/child', 'fr'); // child french
echo $child->parent->locale; // en, there was no proxy
// or we could have translated all existing docs, but then $parent
// would have changed to french by loading the child, weird too...

$child = $dm->findTranslation('/parent/child', 'fr'); // child french
echo $child->parent->locale; // fr
$parent = $dm->find('/parent'); //french from cache

and the list goes on.


so i think we can offer 2 reasonable things:

you can change the default language
$dm->clear();
$dm->setDefaultLocale($locale);
and then use find as usual. no language is tracked but the default
language is what you wanted. when you are done with this language, clear
and set another default.

for findTranslation, you can do 2 modes: get a DETACHED document that
has proxies with languages, but the document and all its annotations and
what you get through them are DETACHED and ignored on flush and can not
be persisted. this way we /can/ have copies of documents in the
different languages. which is nice anyways.

the second mode for findTranslation would be something like ID_ONLY.
instead of the full proxies, you would just get the document ids (=phpcr
path) in the child/parent/reference annotations and be able to load
those documents.
the reason for this is that if we would just put the proxies as normal,
you get the document in whatever langauge it is currently loaded, which
is confusing as hell.

what do you think? does this make sense? can you think of uses cases
that can not be handled by this?

cheers,david

- --

Liip AG // Agile Web Development // T +41 26 422 25 11
CH-1700 Fribourg // PGP 0xA581808B // www.liip.ch
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk7PTEYACgkQqBnXnqWBgIvm7ACgkj4yrUtDsLvKeNBtqpc8AGqU
TY0An0OLy/+fUf0UL8wGoYcW3zz2AlT5
=lbuE
-----END PGP SIGNATURE-----

David Buchmann

unread,
Dec 13, 2011, 5:28:30 AM12/13/11
to symfony-...@googlegroups.com, Brian King
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

hi all,

we worked on this and its now a pull request on phpcr-odm:
https://github.com/doctrine/phpcr-odm/pull/81

feedback is welcome, as is constructive critics :-)

i will merge the pull later this week unless something problematic pops
up in the feedbacks.

cheers,david


Am 16.11.2011 11:19, schrieb Brian King:

- --

Liip AG // Agile Web Development // T +41 26 422 25 11
CH-1700 Fribourg // PGP 0xA581808B // www.liip.ch
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk7nKMoACgkQqBnXnqWBgIvzMgCePstXMELH3UiNScOyG4DudHZ/
BbgAn0fgx2wL1aGyXhONDtL5LbhI3R6w
=S5i3
-----END PGP SIGNATURE-----

David Buchmann

unread,
Dec 18, 2011, 1:53:50 PM12/18/11
to symfony-...@googlegroups.com, Brian King
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

this is now done :-)

https://github.com/doctrine/phpcr-odm/pull/81

i wrote a summary on our blog:

https://blog.liip.ch/archive/2011/12/18/multilanguage-support-for-doctrine-phpcr-odm.html

note that
a) if you already use phpcr-odm, you need to re-run
php bin/phpcr doctrine:phpcr:register-system-node-types
b) there is no support for this in the symfony bundle yet. should not be
too hard to move the DI code from MultilangContentBundle to the
DoctrinePHPCRBundle and add something for the strategies. if nobody
happens to do it, i will do it next year ;-)

cheers,david

Am 16.11.2011 11:19, schrieb Brian King:

- --

Liip AG // Agile Web Development // T +41 26 422 25 11
CH-1700 Fribourg // PGP 0xA581808B // www.liip.ch
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk7uNr4ACgkQqBnXnqWBgItQpwCgwVuEKCPnq5h1Z1AjiMkwRJ/l
GtYAn0OpgAzafTlpfHKRq0oRxhFWHuPJ
=/5Hl
-----END PGP SIGNATURE-----

Reply all
Reply to author
Forward
0 new messages