From: Jacob Wall on
Hello,

I am thinking about adding a language option to a larger library with
many labels, messages, etc. and so far my options that I've thought of
don't look that great. A few scenarios I've considered:

1. Have separate Debug4x projects for the "same" library, one for each
language. The headaches involved with upkeeping each project separately
renders this scenario basically out of the question.

2. Each time in the code when a string is required, check a language
setting variable and provide the correct string. Doable, but there's
gotta be a better way.

3. Debug4x message tables? Can't figure out how to make this work with
conditionals, ie same as No. 2, using a language setting variable, to
use different message tables to pull messages from.

So, No. 1 above, as much of a headache as it would be to upkeep, would
be superior in memory and speed efficiency during operation.

No. 2 would obviously be easier to maintain but the library would grow
in size, almost unnecessarily it would seem as most users I believe
would only require one language, and also would slow down operation,
although not noticeably if only a single string were called but in a
case were multiple strings were needed it could become noticeable.

No. 3, I suppose creating separate libraries with just the messages
might work, then the user could install only the language library
desired. Maybe give each of the message libraries created the same
number so only one could be installed at a time so that in the main
library you would always call the same #xxxxx JstGETTHEMSG, and a check
for the required message library would only mean checking for one.

I have not experimented with any of the options yet, basically realize
it would be a little bit of work so may as well look into it a little,
hopefully get some input from others who have done something like this
before I get too carried away with an inefficient approach.

Any thoughts? Ideas would be appreciated.

Jacob
From: Andreas Möller on
Hello,

> Any thoughts? Ideas would be appreciated.
This can be accomplished easily in several ways.

Two ways are possible for you.

First: A mixture of No. 1 and No. 3:
a) separate all your messages into a separate source file.
( If you are using the inform box editor make sure that the checkmark
in front of M table is *clear* as we will not using the inform box
editor message table functions. Instead use placeholders for all you
message without a space, e.g. Label_with_text. We will then use
defines to call these messages from the message table of the lib. That
way we have total control over our messages. If you need this, then
contact me by private mail as this needs a rather lengthy explanation
and can be easiest explained through some source file examples. )

b) After that create a *.hpp project for each language you desire, it
would contain at least two source files, e.g. ProgramCode.s and
another one for your languages so that you have a clean separation
between your actual program code and the messages you wish to use.
As an example you would have an English.hpp project containing
ProgramCode.s and MessagesEnglish.s and a German.hpp project
containing ProgramCode.s and MessagesGerman.s.

In the 'Project Window' in the 'Project Data' tab in the field
'Message' you can specify which messages will be used for your
library. Put in the name of your Library Message Entry, for example
MyMessages.

c) Now in all your source files for your messages, here
MessagesEnglish.s and MessagesGerman.s you will create the Library
Message Entry by using this code:

ASSEMBLE
= MyMessages
RPL
ARRY ( or LNKARRY if you prefer )
[
"First Message"
"Second Message"
"Third Message"
"and so on"
]

Of course you will use your English messages in MessagesEnglish.s and
of course you will use your German messages in MessagesGerman.s ;-)

d) Accessing the messages: In your program source file, in this
example ProgramCode.s put the following macros at the beginning of
your file *before* your first xNAME or NULLNAME depending on whether
you want to use traditional SASM syntax or MASD syntax:

SASM syntax:
ASSEMBLE
DOMSG MACRO * romid,msgnr * Macro, to handle msg nr. generation
CON(5) =DOBINT
CON(5) ($1)*256+($2)
DOMSG ENDM
RPL

MASD syntax:
* Count for the Message Table
ASSEMBLEM DC RomIdx256 100*RomId !RPL ( 100h = 256d )

In both 'RomId' is fetched from the library number that you use and
which is the number you have given the field RomId in the 'Project
Window' in the 'Project Data' tab.

Now if you want to access a message in your source file you will use
the following construct depending on whether you want to use
traditional SASM syntax or MASD syntax:

SASM syntax:
ASSEMBLE
DOMSG RomId,1 ( #BINT for your first message )
RPL

ASSEMBLE
DOMSG RomId,2 ( #BINT for your second message )
RPL

ASSEMBLE
DOMSG RomId,3 ( #BINT for your third message )
RPL

MASD syntax:

ASSEMBLEM $(5)DOBINT $(5)RomIdx256+#1 !RPL ( #BINT for your first
message )
ASSEMBLEM $(5)DOBINT $(5)RomIdx256+#2 !RPL ( #BINT for your second
message )
ASSEMBLEM $(5)DOBINT $(5)RomIdx256+#3 !RPL ( #BINT for your third
message )


Of course you might want to call JstGETTHEMSG afterwards depending on
what you need (The menu and the POL and some other built-in stuff can
work directly with #MessageBINTs).

Note that you can use conditional assembly for this, too. But the
above is a lot easier to handle then to fiddle with the parameters for
conditional assembly in debug4x and that is the reason I omit it here.



Second: No. 2
Usually the message table pointer of a library ( which is stored in
the ROMPTAB of the calculator ) points to the Library Message Entry
you provide. But this pointer can point anywhere. If you want multiple
message tables ( which would be equal to using more than 255 (FFh)
messages ) you can hot switch to another message table by changing
this pointer to any NULLNAME of your lib where your additional
messages are stored in an array. To access a single message of each
table use the same mechanism as described in the first solution. Be
aware that, for example, JstGETTHEMSG fetches the messages from the
current active message table that is stored in the ROMPTAB.
To exchange the message table pointer in the ROMPTAB ( to enable hot
switching ) you need some Saturn assembly code and also you might
consider storing the pointers of the different messages tables in some
reserved RAM areas while your program is running for faster access /
switching.

I suggest that you use the first solution I mentioned as this is
easier to code and as most likely libraries do not contain more than
255 (FFh) messages. Also this has the benefit, as you mentioned, that
the binary is smaller as it contains only the messages of the desired
language. Maintaining is easy as you have the same program code for
all projects and a specific language file. Just compile each project
to a unique binary ( example: TreeBrowserEN, TreeBrowserDE ) and there
you go.


HTH,
Andreas
http://www.software49g.gmxhome.de
From: Jacob Wall on
On 05/05/2010 1:55 AM, Andreas M�ller wrote:
> Hello,
>
>> Any thoughts? Ideas would be appreciated.
> This can be accomplished easily in several ways.
>
> Two ways are possible for you.
>
> First: A mixture of No. 1 and No. 3:
> a) separate all your messages into a separate source file.
> ( If you are using the inform box editor make sure that the checkmark
> in front of M table is *clear* as we will not using the inform box
> editor message table functions. Instead use placeholders for all you
> message without a space, e.g. Label_with_text. We will then use
> defines to call these messages from the message table of the lib. That
> way we have total control over our messages. If you need this, then
> contact me by private mail as this needs a rather lengthy explanation
> and can be easiest explained through some source file examples. )
>
> b) After that create a *.hpp project for each language you desire, it
> would contain at least two source files, e.g. ProgramCode.s and
> another one for your languages so that you have a clean separation
> between your actual program code and the messages you wish to use.
> As an example you would have an English.hpp project containing
> ProgramCode.s and MessagesEnglish.s and a German.hpp project
> containing ProgramCode.s and MessagesGerman.s.
>
> In the 'Project Window' in the 'Project Data' tab in the field
> 'Message' you can specify which messages will be used for your
> library. Put in the name of your Library Message Entry, for example
> MyMessages.
>
> c) Now in all your source files for your messages, here
> MessagesEnglish.s and MessagesGerman.s you will create the Library
> Message Entry by using this code:
>
> ASSEMBLE
> = MyMessages
> RPL
> ARRY ( or LNKARRY if you prefer )
> [
> "First Message"
> "Second Message"
> "Third Message"
> "and so on"
> ]
>
> Of course you will use your English messages in MessagesEnglish.s and
> of course you will use your German messages in MessagesGerman.s ;-)
>
> d) Accessing the messages: In your program source file, in this
> example ProgramCode.s put the following macros at the beginning of
> your file *before* your first xNAME or NULLNAME depending on whether
> you want to use traditional SASM syntax or MASD syntax:
>
> SASM syntax:
> ASSEMBLE
> DOMSG MACRO * romid,msgnr * Macro, to handle msg nr. generation
> CON(5) =DOBINT
> CON(5) ($1)*256+($2)
> DOMSG ENDM
> RPL
>
> MASD syntax:
> * Count for the Message Table
> ASSEMBLEM DC RomIdx256 100*RomId !RPL ( 100h = 256d )
>
> In both 'RomId' is fetched from the library number that you use and
> which is the number you have given the field RomId in the 'Project
> Window' in the 'Project Data' tab.
>
> Now if you want to access a message in your source file you will use
> the following construct depending on whether you want to use
> traditional SASM syntax or MASD syntax:
>
> SASM syntax:
> ASSEMBLE
> DOMSG RomId,1 ( #BINT for your first message )
> RPL
>
> ASSEMBLE
> DOMSG RomId,2 ( #BINT for your second message )
> RPL
>
> ASSEMBLE
> DOMSG RomId,3 ( #BINT for your third message )
> RPL
>
> MASD syntax:
>
> ASSEMBLEM $(5)DOBINT $(5)RomIdx256+#1 !RPL ( #BINT for your first
> message )
> ASSEMBLEM $(5)DOBINT $(5)RomIdx256+#2 !RPL ( #BINT for your second
> message )
> ASSEMBLEM $(5)DOBINT $(5)RomIdx256+#3 !RPL ( #BINT for your third
> message )
>
>
> Of course you might want to call JstGETTHEMSG afterwards depending on
> what you need (The menu and the POL and some other built-in stuff can
> work directly with #MessageBINTs).
>
> Note that you can use conditional assembly for this, too. But the
> above is a lot easier to handle then to fiddle with the parameters for
> conditional assembly in debug4x and that is the reason I omit it here.
>
>
>
> Second: No. 2
> Usually the message table pointer of a library ( which is stored in
> the ROMPTAB of the calculator ) points to the Library Message Entry
> you provide. But this pointer can point anywhere. If you want multiple
> message tables ( which would be equal to using more than 255 (FFh)
> messages ) you can hot switch to another message table by changing
> this pointer to any NULLNAME of your lib where your additional
> messages are stored in an array. To access a single message of each
> table use the same mechanism as described in the first solution. Be
> aware that, for example, JstGETTHEMSG fetches the messages from the
> current active message table that is stored in the ROMPTAB.
> To exchange the message table pointer in the ROMPTAB ( to enable hot
> switching ) you need some Saturn assembly code and also you might
> consider storing the pointers of the different messages tables in some
> reserved RAM areas while your program is running for faster access /
> switching.
>
> I suggest that you use the first solution I mentioned as this is
> easier to code and as most likely libraries do not contain more than
> 255 (FFh) messages. Also this has the benefit, as you mentioned, that
> the binary is smaller as it contains only the messages of the desired
> language. Maintaining is easy as you have the same program code for
> all projects and a specific language file. Just compile each project
> to a unique binary ( example: TreeBrowserEN, TreeBrowserDE ) and there
> you go.
>
>
> HTH,
> Andreas
> http://www.software49g.gmxhome.de

Thank you Andreas, and yes that certainly does help. Now I have a good
idea of how to proceed, your explanations are very clear.

Your first method does indeed sound simpler and I will most likely
pursue that route, although the possibility of hot switching message
tables might be something to keep in mind also, and as suspected it
cannot be done with System RPL.

I may contact you when I get to start implementing this. It could be
some time however since I've got a few other things on the go first.

I appreciate your valuable input.

Jacob
From: Andreas Möller on
Hello,

a third possibility would be to use a linked array containing your
multiple languages as supported by the operating system.
This would mean that you could have a maximum of three different
languages (IIRC) in a message table and in total no more than 255
(#FFh) messages in one table. (Hot switching might be possible.) For
switching you languages you could then use the built-in commands -
>LANGUAGE.

But I would not encourage you for this solution, again I would
strongly advise method one as this is easiest to program and more
important, easiest to maintain.

Regards,
Andreas
http://www.software49g.gmxhome.de
From: Jacob Wall on
On 05/05/2010 11:15 PM, Andreas M�ller wrote:
> Hello,
>
> a third possibility would be to use a linked array containing your
> multiple languages as supported by the operating system.
> This would mean that you could have a maximum of three different
> languages (IIRC) in a message table and in total no more than 255
> (#FFh) messages in one table. (Hot switching might be possible.) For
> switching you languages you could then use the built-in commands -
>> LANGUAGE.
>
> But I would not encourage you for this solution, again I would
> strongly advise method one as this is easiest to program and more
> important, easiest to maintain.
>
> Regards,
> Andreas
> http://www.software49g.gmxhome.de

I had thought of somehow using the built in LANGUAGE setting but felt
that would be tricky to pull off.

The 255 maximum thing is a concern before I even get going so I
experimented a little and realized that I could use tricks like this for
menus for example:

xNAME msg1
::
#xxx01
JstGETTHEMSG
DOSTR>
;

NULLNAME Messages
ARRY
[
"{ \22ONE\22 \22TWO\22 \22THREE\22 }"
]

To think that each menu key label should take up a valuable 1/255 was
troublesome, haha. Mind you not all labels would require translation.

Jacob