Re: [Pharo-users] i18n tools

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-users] i18n tools

Mariano Martinez Peck
Panu, maybe you may want to cc seaside mailing list too ;)

On Fri, Sep 10, 2010 at 2:41 PM, Panu Suominen <[hidden email]> wrote:
2010/9/10 Stanislav Paskalev <[hidden email]>:
> Seaside had none the last time I asked. Please do so.

I am in a bit hurry, but I hope you can still make sense out of this.

The whole seaside and translation thing is based on the fact that
Seaside render: method is dispatched to objects renderOn: method where
we can access session. On the other hand
we can store language to session. If we implement object that is able
to answer correctly to translate: -message with language as a
parameter we have a simple translation framework.

I created a simple translation framework which is able to return
translation for certain key. Keys are looked from properly named
subclass. Names are form of LanguagePackOfProgramX_fi,
LanguagePackOfProgramX_en. Each containing translations for the given
language. K3LanguagePack and tests should give better idea.

Notice that examples below need language -method in session....

Example to use with seaside:

renderContentOn: html
   html render: (LanguegPackOfMyProgram translationFor: #greetingMessge)


Example with magritte:
descriptionEmail
      ^MAStringDescription new
               accessor: #email;
               label: (K3CoreLanguagePack translationFor: #email);
               addCondition: [:value | value includes: $@] labelled:
(LanguegPackOfMyProgram translationFor: #emailNotValid);
               beRequired; requiredErrorMessage:
(LanguegPackOfMyProgram translationFor: #emailIsRequired);
               priority: 10;
               yourself.


The magritte part was builded on top of 2.0.5 magritte-seaside.

This code enabled me to build seaside application demo that could
change its user interface on the fly. Meaning that anything else stays
as it is, only the language changes.
But I don't know how useful this is for other people.

Currently the major flaw is that there is no way to set the arguments
for the translation ('Hello user, your name is {1}'). It is not a big
addition but haven't needed it in this proof of concept. However it
should not be very hard to implement.

Other thing that should be discussed is the way translations are
stored. I chose to use symbols that points to methods and thus
translations can be encapsulated in classes. However there seems to be
NaturalLanguageTranslator and string translate already in existence
and I am wondering should I change the implementation to use them
instead.

I am very open to suggestions.

--
Panu

_______________________________________________
Pharo-users mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-users



_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

i18n tools

Panu Suominen-3
To keep the story short. I did not find any tools to use translations in 
seaside and magritte so I had to made something up on my own.

I am skeptic wether it will have any value beyond myself but comments are very welcome.
There is more explanation in the following conversation:
(pharo-project subscribers, sorry for double post).


Forwarded conversation
Subject: i18n tools
------------------------

From: Panu Suominen <[hidden email]>
Date: 2010/9/9
To: [hidden email]


I am researching wether out team could start using Pharo. I have tried to locate
some tools to do user interface translations but I did not find
anything in time so I had
to develop some rudimentary key-based translation tools my self. I would like
to know is this lack of translation tools reality and if others are having same
kind of problems?

--
Panu

----------
From: Stéphane Ducasse <[hidden email]>
Date: 2010/9/9
To: [hidden email], A friendly place where any question about pharo is welcome <[hidden email]>
Cc: Hilaire Fernandes <[hidden email]>


hilaire

can you provide some pointers because you did a lot of translations.

Stef
> _______________________________________________
> Pharo-users mailing list
> [hidden email]
> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-users


----------
From: Panu Suominen <[hidden email]>
Date: 2010/9/10
To: Stéphane Ducasse <[hidden email]>
Cc: A friendly place where any question about pharo is welcome <[hidden email]>, Hilaire Fernandes <[hidden email]>


To stimulate little more.. I have done rudimentary translation support
for magritte and seaside.
Should I publish them or are there already working options?

--
Panu

----------
From: Stanislav Paskalev <[hidden email]>
Date: 2010/9/10
To: [hidden email], A friendly place where any question about pharo is welcome <[hidden email]>


Seaside had none the last time I asked. Please do so.

Stanislav Paskalev

----------
From: Panu Suominen <[hidden email]>
Date: 2010/9/10
To: Stanislav Paskalev <[hidden email]>
Cc: A friendly place where any question about pharo is welcome <[hidden email]>


2010/9/10 Stanislav Paskalev <[hidden email]>:
I am in a bit hurry, but I hope you can still make sense out of this.

The whole seaside and translation thing is based on the fact that
Seaside render: method is dispatched to objects renderOn: method where
we can access session. On the other hand
we can store language to session. If we implement object that is able
to answer correctly to translate: -message with language as a
parameter we have a simple translation framework.

I created a simple translation framework which is able to return
translation for certain key. Keys are looked from properly named
subclass. Names are form of LanguagePackOfProgramX_fi,
LanguagePackOfProgramX_en. Each containing translations for the given
language. K3LanguagePack and tests should give better idea.

Notice that examples below need language -method in session....

Example to use with seaside:

renderContentOn: html
   html render: (LanguegPackOfMyProgram translationFor: #greetingMessge)


Example with magritte:
descriptionEmail
      ^MAStringDescription new
               accessor: #email;
               label: (K3CoreLanguagePack translationFor: #email);
               addCondition: [:value | value includes: $@] labelled:
(LanguegPackOfMyProgram translationFor: #emailNotValid);
               beRequired; requiredErrorMessage:
(LanguegPackOfMyProgram translationFor: #emailIsRequired);
               priority: 10;
               yourself.


The magritte part was builded on top of 2.0.5 magritte-seaside.

This code enabled me to build seaside application demo that could
change its user interface on the fly. Meaning that anything else stays
as it is, only the language changes.
But I don't know how useful this is for other people.

Currently the major flaw is that there is no way to set the arguments
for the translation ('Hello user, your name is {1}'). It is not a big
addition but haven't needed it in this proof of concept. However it
should not be very hard to implement.

Other thing that should be discussed is the way translations are
stored. I chose to use symbols that points to methods and thus
translations can be encapsulated in classes. However there seems to be
NaturalLanguageTranslator and string translate already in existence
and I am wondering should I change the implementation to use them
instead.

I am very open to suggestions.

--
Panu

----------
From: Mariano Martinez Peck <[hidden email]>
Date: 2010/9/10
To: [hidden email], A friendly place where any question about pharo is welcome <[hidden email]>
Cc: Seaside - general discussion <[hidden email]>


Panu, maybe you may want to cc seaside mailing list too ;)






--
Panu

_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside

Korppi-Translation-PanuSuominen.4.1.cs (12K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-users] i18n tools

Panu Suominen-3
In reply to this post by Mariano Martinez Peck
2010/9/10 Hilaire Fernandes <[hidden email]>:
> Check with Philip Marchall, he did modification to use gettext code with
> Seaside.

Ok. Thanks to all for the help. Seaside and gettext are apparently the magic
words that solves this problem. :)

http://forum.world.st/Seaside-Gettext-sneak-peak-td2164600.html

--
Panu
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-users] i18n tools

Philippe Marschall
2010/9/10 Panu Suominen <[hidden email]>:
> 2010/9/10 Hilaire Fernandes <[hidden email]>:
>> Check with Philip Marchall, he did modification to use gettext code with
>> Seaside.
>
> Ok. Thanks to all for the help. Seaside and gettext are apparently the magic
> words that solves this problem. :)
>
> http://forum.world.st/Seaside-Gettext-sneak-peak-td2164600.html

I believe you can not get gettext from here [1]. The repo for
Seaside-Gettext is still the same.

 [1] http://www.squeaksource.com/PharoNonCorePackages

Cheers
Philippe
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-users] i18n tools

Panu Suominen-3
2010/9/11 Philippe Marschall <[hidden email]>:
> I believe you can not get gettext from here [1].
Why is that? Following code seemed to do the loading fine.
Gofer new squeaksource: 'PharoNonCorePackages'; package:
'ConfigurationOfGettext'; load.
((Smalltalk at: #ConfigurationOfGettext) project version:'1.0') load.

Couple of questions:
1) What is the preferred method to use variable content in strings? Is it:
         'The time now is {1}' translated format: {Time now}

2) Is there already a plan to support above kind of parametrisation in Seaside?
3) Is there a way to translate magrittes validation errors?

Does it seem good idea to create class that is going to be translated
(but not yet is) and the translation
is resolved later. For example when seaside's render: method is
called. This way magritte errors
could be transalted when they get rendered. Actually translated method
could return this
kind of objects and the resulting object's asString (printOn:) and
renderOn: could do the actual
translation

With same kind of idea one could also pass the arguments to the actual
translation. For example
t := 'The time is now {1}' translatedWith:{[Time now]}
"in seaside:"
html render: t

Does this make any sense? Or is there already a better solution/plan?
--
Panu
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-users] i18n tools

Philippe Marschall
2010/9/11 Panu Suominen <[hidden email]>:
> 2010/9/11 Philippe Marschall <[hidden email]>:
>> I believe you can not get gettext from here [1].
> Why is that?

Dunno, ask Hilaire.

> Following code seemed to do the loading fine.
> Gofer new squeaksource: 'PharoNonCorePackages'; package:
> 'ConfigurationOfGettext'; load.
> ((Smalltalk at: #ConfigurationOfGettext) project version:'1.0') load.
>
> Couple of questions:
> 1) What is the preferred method to use variable content in strings? Is it:
>         'The time now is {1}' translated format: {Time now}

Variable content is not supported, that's mainly a Gettext issue. You
can use the above code but ignores the locale of the session, the
result will probably be a bit underwhelming

> 2) Is there already a plan to support above kind of parametrisation in Seaside?

Once Gettext supports it, yes.

> 3) Is there a way to translate magrittes validation errors?

Not out of the box. You'd probably have to customize Magritte error rendering.

> Does it seem good idea to create class that is going to be translated
> (but not yet is) and the translation
> is resolved later. For example when seaside's render: method is
> called. This way magritte errors
> could be transalted when they get rendered. Actually translated method
> could return this
> kind of objects and the resulting object's asString (printOn:) and
> renderOn: could do the actual
> translation

I don't quite follow.

> With same kind of idea one could also pass the arguments to the actual
> translation. For example
> t := 'The time is now {1}' translatedWith:{[Time now]}
> "in seaside:"
> html render: t
>
> Does this make any sense? Or is there already a better solution/plan?

Again, once Gettext supports it, I'd be happy to add support for it in
Seaside-Gettext.

Cheers
Philippe
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-users] i18n tools

Panu Suominen-3
2010/9/11 Philippe Marschall <[hidden email]>:
>> Does it seem good idea to create class that is going to be translated
>> (but not yet is) and the translation
>> is resolved later.
> I don't quite follow.

Ok. I try to explain my idea better. With magritte you have to spell
out the error messages before you know anything about the locale of
the user who is going to see the messages. One can of course write
those error messages as plain strings and then write alternative
seaside component to translate the string later. However with this
kind of aproach there is no way to extract the translations for .pot
file.

This problem (and the need for special translate: -seside method)
would go away if the String translate method would return object that
translates itself when the actual translated version is needed
(basically printOn: and renderOn: methods).

The main parts of the effective code would be something like this:

String>>translated
"answer the receiver translated to the default language"
        ^LazyTranslation fromString: self.

LazyTranslation>>renderOn: html
        html text: (self translate: WACurrentLocalizationContext value localeID).

LazyTranslation>>printOn: aStream
        ^self translate.

LazyTranslation>>translate
        ^(NaturalLanguageTranslator translate: msgid).

LazyTranslation>>translate: localeID
        ^(NaturalLanguageTranslator translate: msgid to: localeID).


Of course LazyTranslation should have to fake it string nature with
additional methods. The goal of this approach is simply decouple the
creation of translation and printing it using some locale. I hope this
made more sense.


--
Panu
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-users] i18n tools

Boris Popov, DeepCove Labs (SNN)
In reply to this post by Mariano Martinez Peck
Re: [Seaside] Re: [Pharo-users] i18n tools

VisualWorks has UserMessage that renders actual translated string based on the current process' locale (provided a matching catalog in that locale is available, of course) which is set by the session (technically a filter on the session). It also has an optional default string to support lazy catalog implementation. UserMessage instance can be created in code via,

#CatalogKey << #CatalogName >> 'Default String'

or,

#CatalogKey << #CatalogName

-Boris (via BlackBerry)

----- Original Message -----
From: [hidden email] <[hidden email]>
To: Philippe Marschall <[hidden email]>
Cc: Seaside - general discussion <[hidden email]>; Hilaire Fernandes <[hidden email]>
Sent: Sat Sep 11 22:58:00 2010
Subject: Re: [Seaside] Re: [Pharo-users] i18n tools

2010/9/11 Philippe Marschall <[hidden email]>:
>> Does it seem good idea to create class that is going to be translated
>> (but not yet is) and the translation
>> is resolved later.
> I don't quite follow.

Ok. I try to explain my idea better. With magritte you have to spell
out the error messages before you know anything about the locale of
the user who is going to see the messages. One can of course write
those error messages as plain strings and then write alternative
seaside component to translate the string later. However with this
kind of aproach there is no way to extract the translations for .pot
file.

This problem (and the need for special translate: -seside method)
would go away if the String translate method would return object that
translates itself when the actual translated version is needed
(basically printOn: and renderOn: methods).

The main parts of the effective code would be something like this:

String>>translated
"answer the receiver translated to the default language"
        ^LazyTranslation fromString: self.

LazyTranslation>>renderOn: html
        html text: (self translate: WACurrentLocalizationContext value localeID).

LazyTranslation>>printOn: aStream
        ^self translate.

LazyTranslation>>translate
        ^(NaturalLanguageTranslator translate: msgid).

LazyTranslation>>translate: localeID
        ^(NaturalLanguageTranslator translate: msgid to: localeID).


Of course LazyTranslation should have to fake it string nature with
additional methods. The goal of this approach is simply decouple the
creation of translation and printing it using some locale. I hope this
made more sense.


--
Panu
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside


_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-users] i18n tools

Philippe Marschall
In reply to this post by Panu Suominen-3
2010/9/12 Panu Suominen <[hidden email]>:
> 2010/9/11 Philippe Marschall <[hidden email]>:
>>> Does it seem good idea to create class that is going to be translated
>>> (but not yet is) and the translation
>>> is resolved later.
>> I don't quite follow.
>
> Ok. I try to explain my idea better. With magritte you have to spell
> out the error messages before you know anything about the locale of
> the user who is going to see the messages.

Nope. The locale is set before the Magritte code even kicks in.

> One can of course write
> those error messages as plain strings and then write alternative
> seaside component to translate the string later. However with this
> kind of aproach there is no way to extract the translations for .pot
> file.
>
> This problem (and the need for special translate: -seside method)
> would go away if the String translate method would return object that
> translates itself when the actual translated version is needed
> (basically printOn: and renderOn: methods).
>
> The main parts of the effective code would be something like this:
>
> String>>translated
> "answer the receiver translated to the default language"
>        ^LazyTranslation fromString: self.

Override in String, not gonna happen.

> LazyTranslation>>renderOn: html
>        html text: (self translate: WACurrentLocalizationContext value localeID).
>
> LazyTranslation>>printOn: aStream
>        ^self translate.
>
> LazyTranslation>>translate
>        ^(NaturalLanguageTranslator translate: msgid).
>
> LazyTranslation>>translate: localeID
>        ^(NaturalLanguageTranslator translate: msgid to: localeID).
>
>
> Of course LazyTranslation should have to fake it string nature with
> additional methods. The goal of this approach is simply decouple the
> creation of translation and printing it using some locale. I hope this
> made more sense.

Cheers
Philippe
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-users] i18n tools

Panu Suominen-3
>> Ok. I try to explain my idea better. With magritte you have to spell
>> out the error messages before you know anything about the locale of
>> the user who is going to see the messages.
>
> Nope. The locale is set before the Magritte code even kicks in.

Yes, there is some locale at the time magritte reads the meta-data and
creates the component, but this locale might not be the locale user wants
to use in user interface. User might change the locale/language for
the session but this does not affect the magritte
code because the error messages are created with different locale.
And I think that is a problem.

Or is there something I don't understand?

--
Panu
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-users] i18n tools

stephane ducasse
In reply to this post by Philippe Marschall
Translation is not limited to seaside?

>
>>> I believe you can not get gettext from here [1].
>> Why is that?
>
> Dunno, ask Hilaire.
>
>> Following code seemed to do the loading fine.
>> Gofer new squeaksource: 'PharoNonCorePackages'; package:
>> 'ConfigurationOfGettext'; load.
>> ((Smalltalk at: #ConfigurationOfGettext) project version:'1.0') load.

_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-users] i18n tools

Panu Suominen-3
Because of the responses I have received here, I am pretty sure the
code I attached has no use for others, but
I decided to send it here anyways. I have had such hard time to find
any resources about translating text in seaside
that this can not make the situation much worse. :)

Attached change set will add asTranslation method to String class.
This method will create LazyTranslation
which does the actual translation "on the fly" when needed.

This approach enables seaside to translate text without using
translate: -method, but remember to use
the WALocalizationContextFilter with the application. Using render:
-will render the text
with the locale used by the session and text: will use the local of the image.

Also magritte forms get translated correctly without any modifications
to the magritte code. To use it write
descriptions following way:

descriptionEmail
        ^MAStringDescription new
                accessor: #email;
                label: 'Email' asTranslation;
                addCondition: [:value | value includes: $@] labelled: 'Email is not
valid.' asTranslation;
                beRequired;
                priority: 10;
                yourself.

I know that the code is bad, but I really needed the feature. At least
I hope that I get a lots of reasons why
the approach I have taken is really a wrong way to go. Sorry to bother
you with this so much.

--
Panu

_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside

gettext-translation.1.cs (3K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-users] i18n tools

Philippe Marschall
In reply to this post by Panu Suominen-3
2010/9/12 Panu Suominen <[hidden email]>:

>>> Ok. I try to explain my idea better. With magritte you have to spell
>>> out the error messages before you know anything about the locale of
>>> the user who is going to see the messages.
>>
>> Nope. The locale is set before the Magritte code even kicks in.
>
> Yes, there is some locale at the time magritte reads the meta-data and
> creates the component, but this locale might not be the locale user wants
> to use in user interface. User might change the locale/language for
> the session but this does not affect the magritte
> code because the error messages are created with different locale.
> And I think that is a problem.
>
> Or is there something I don't understand?

I see what you mean. The other question is of course whether Magritte
would work with a LazyTranslation where a String is expected. Sure you
can try to be clever and subclass String or ProtoObject but that will
probably break at some point. Maybe a better way would be a method
like #markForLaterTranslation that would answer the receiver but also
export it into the .po file?

Cheers
Philippe
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-users] i18n tools

Panu Suominen-3
2010/9/12 Philippe Marschall <[hidden email]>:
> I see what you mean. The other question is of course whether Magritte
> would work with a LazyTranslation where a String is expected.

It only passes the strings along. It does not do any operations to them.
At least I haven't bumbed in to a case where it would alter the string.
But of course this behaviour might change but then translating the text
would also be a problem.

Could you think something that might get broken in the future? I think
the approach
is vulnerable to calls that alter and copy the string, but in many
cases it would
brake the current translation system also.

> Maybe a better way would be a method
> like #markForLaterTranslation that would answer the receiver but also
> export it into the .po file?

It is other possibility and I thought it also. I see couple of problems.
If markForLaterTranslation does not mark the object in any way it
would be hard to determine in which cases text should be translated.
This can create situation
where text gets no translation or gets translated twice or more.
It requires quite many changes to code. User interface code has to be
changed to take care translations. And when translation logic is
changed the user interface code has to be changed too.
For example when arguments are added to translations #translate:
-method of seaside has to be changed too. I think this will divide the
logic to several places.


--
Panu
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside