Brass Translation

One suite to code them all. An complete IDE and assembler for all your z80 projects!

Moderators: benryves, kv83

Post Reply
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Brass Translation

Post by benryves »

I'm currently in the process of adding better internationalisation support to Brass 3 (well, it's a side-effect of cleaning up the code). Bear in mind that the following won't actually work with beta 6, and doesn't cover any of the bundled plugins. I release this information to see if anyone is interested, and if they are to get a start on creating a translation, and will release an internationalisation-friendly Brass soon (along with internationalisation-friendly plugins).

If you want to have Brass display messages in your native language, you will be able to drop in a satellite assembly containing translated resource strings.

Unfortunately, to do this you'll need the .NET or Windows SDK (download) but I'll post a resource file (.txt) and if you send it back to me with the replaced strings I'll compile it for you. It might be possible to write an resource compiler plugin for Brass itself, but I'm having difficulties emitting assemblies with a culture set (the only way I can do this is via the AL class, which requires the SDK anyway).

Basically, you need to compile a resource file into an assembly. Let's assume you were going to create a French translation of Brass. France has the general culture identifier "fr".

Create a text file with the name "Brass3.Strings.culture.txt" (in this case, "Brass3.Strings.fr.txt"). In this file should be Key=Value pair lines translating the application's resources. Here's the current default resource file (en-GB):

Code: Select all

CommandLineCalculatorMode=Running in interactive calculator mode. Type exit to quit.
CommandLineError=Error in {1} line {2} column {3}: {0}
CommandLineFatalError=Fatal Error.
CommandLineSyntax=Usage: Brass ProjectFile
CommandLineWarning=Warning in {1} line {2} column {3}: {0}
ErrorArgumentCountMismatch=Expected {0} argument(s).
ErrorArgumentCountMismatchEndlessRange=Expected {0} or more arguments.
ErrorArgumentCountMismatchRange=Expected {0} to {1} argument(s).
ErrorArgumentExpectedPositive=Argument {0} must be positive.
ErrorArgumentExpectedSingleToken=Expected a single token value for argument {0}.
ErrorArgumentExpectedSingleTokenAndIndex=Couldn't extract a single token and index.
ErrorArgumentOptionalNotLast=Argument types cannot have mandatory arguments following optional arguments
ErrorArgumentRepeatForeverNotLast=RepeatForever can only apply to the last argument.
ErrorArgumentUnsupportedType=Argument type {0} not supported.
ErrorAssemblerNotSet=No assembler set.
ErrorAssemblerNotSetAssumeDefault=Assembler not explicitly set, so assuming {0}.
ErrorAutomaticStringEncoderIsMultibyte=Automatically wrapped encodings must be single-byte only.
ErrorBaseMustByTwoEightSixteen=Must be base 2, 8 or 16.
ErrorBracketExpected=This token isn't an open or close bracket.
ErrorBracketMismatch=Brackets don't match.
ErrorBracketNotClosed=Matching closing bracket not found.
ErrorBracketStartIndexOutOfBounds=Invalid starting bracket index.
ErrorCancellingBuild={0} error(s) found: Cancelling build.
ErrorDirectiveNotDeclared=Directive '{0}' not declared.
ErrorEnvironmentNotSetTemplates=Environment variable Brass.Templates not set.
ErrorEvaluationAccessorLabelNotFound=No label found for label access operator.
ErrorEvaluationAssignmentsNotPermitted=You cannot perform assignments in this expression.
ErrorEvaluationExpectedFieldAccess=Expected field access.
ErrorEvaluationExpectedOperandAfterOperator=Expected operand after operator.
ErrorEvaluationExpectedOperandBeforeOperator=Expected operand before operator.
ErrorEvaluationFunctionNotDeclared=Function '{0}' not declared.
ErrorEvaluationMissingConditionalOperator=Missing matching conditional operator '?'.
ErrorEvaluationNoSingleResult=Syntax error.
ErrorEvaluationNothingToEvaluate=Nothing to evaluate.
ErrorEvaluationOperandsUnsupported={0} operands unsupported.
ErrorEvaluationTypeInformationMissing=Couldn't get type information.
ErrorExpectedAssignment=An assignment must be made.
ErrorFieldNotDeclared=Field '{0}' not defined.
ErrorFlowControlDisabled=Flow control has been temporarily disabled.
ErrorLabelAlreadyDefined=Duplicate label '{0}'.
ErrorLabelCannotParse=Could not parse '{0}'.
ErrorLabelCannotRemoveOutputCounter=You cannot remove the predefined output counter label.
ErrorLabelCannotRemoveProgramCounter=You cannot remove the predefined program counter label.
ErrorLabelInvalidNameNumber=Invalid name '{0}' (looks like a number).
ErrorLabelIsConstant=Label '{0}' is constant and cannot be assigned to.
ErrorLabelNotFound=Label '{0}' not found.
ErrorLabelPageNotFound=Page value for label '{0}' not found.
ErrorLabelReusableAlreadyExistsAtPosition=A reusable label already exists at this position.
ErrorLabelReusableInvalidClass='{0}' is not a valid reusable label class.
ErrorLabelReusableInvalidName=Invalid reusable label name.
ErrorLabelReusableNotFound=Couldn't get value for reusable label '{0}'.
ErrorMacroAlreadyDefined=Macro {0} already defined.
ErrorModuleAlreadyAtTopLevel=Already at the top module level.
ErrorOnlyLoadDuringInitialPass=You can only load and compile a file during the initial pass.
ErrorOutputFilenameNotSet=Output filename not specified.
ErrorPluginAlreadyAliased=Plugin '{0}' already loaded.
ErrorPluginNotFound=Plugin '{0}' not found.
ErrorProjectInvalidBuildConfigurationComponent=Invalid build configuration component '{0}'.
ErrorProjectTemplateNotFound=Could not load template {0}.
ErrorTokenTypeToInstruction=Type can only be set to TokenType.Instruction by assembler plugins.
ErrorUnspecifiedName=No name specified.
WarningPluginLoadedTwice=Plugin '{0}' loaded twice.
Make sure you save the file using the UTF-8 encoding.

There are two stages to turning this file into a satellite assembly. First you need to turn it into a valid .resources file, done with the tool resgen:

Code: Select all

resgen Brass3.Strings.culture.txt
Now you have a .resources file, you can use the assembler linker tool to embed the file into an assembly:

Code: Select all

al /t:lib /embed:Brass3.Strings.culture.resources /culture:culture /out:Brass.resources.dll
Or, with the above French example:

Code: Select all

C:\>resgen Brass3.Strings.fr.txt
Read in 62 resources from "Brass3.Strings.fr.txt"
Writing resource file...  Done.

C:\>al /t:lib /embed:Brass3.Strings.fr.resources /culture:fr /out:Brass.resources.dll
Microsoft (R) Assembly Linker version 8.00.50727.312
for Microsoft (R) Windows (R) .NET Framework version 2.0.50727
Copyright (C) Microsoft Corporation 2001-2003. All rights reserved.

C:\>
You must set the assembly culture! If you are producing a translation for a subculture (eg US English) the culture name is in the form en-US.

The last stage is to copy the satellite assembly to the correct location, which is BrassDir\culture\Brass.resources.dll. To continue the example above:

Code: Select all

C:\Program Files\Brass\Brass.exe                 ; Main Brass executable.
C:\Program Files\Brass\de\Brass.resources.dll    ; German translation.
C:\Program Files\Brass\nl\Brass.resources.dll    ; Dutch translation.
C:\Program Files\Brass\nl-BE\Brass.resources.dll ; Dutch (Belgian) translation.
King Harold
Calc King
Posts: 1513
Joined: Sat 05 Aug, 2006 7:22 am

Post by King Harold »

No offense, but what's the use of this?
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

Some people might rather see the error messages displayed in their own language rather than English, that's all. :)

No extra code needs to be written, it's a feature of the .NET runtime environment.
User avatar
Timendus
Calc King
Posts: 1729
Joined: Sun 23 Jan, 2005 12:37 am
Location: Netherlands
Contact:

Post by Timendus »

To don't expect anyone to want this... but what the heck ;)

Dutch translation:

Code: Select all

CommandLineCalculatorMode=Interactieve rekenmachine modus. Type exit om af te sluiten.
CommandLineError=Error in {1} regel {2} kolom {3}: {0}
CommandLineFatalError=Fatale error.
CommandLineSyntax=Gebruik: Brass ProjectFile
CommandLineWarning=Waarschuwing in {1} regel {2} kolom {3}: {0}
ErrorArgumentCountMismatch=Verwachtte {0} argument(en).
ErrorArgumentCountMismatchEndlessRange=Verwachtte {0} of meer argument(en).
ErrorArgumentCountMismatchRange=Verwachtte {0} tot {1} argument(en).
ErrorArgumentExpectedPositive=Argument {0} moet positief zijn.
ErrorArgumentExpectedSingleToken=Verwachtte een waarde van één token voor argument {0}.
ErrorArgumentExpectedSingleTokenAndIndex=Kon geen enkele token en index ontwaren? (Couldn't extract a single token and index).
ErrorArgumentOptionalNotLast=Argumenttypen kunnen geen verplichtte argumenten hebben na optionele argumenten.
ErrorArgumentRepeatForeverNotLast=RepeatForever kan alleen op het laatste argument slaan.
ErrorArgumentUnsupportedType=Argumenttype {0} wordt niet ondersteund.
ErrorAssemblerNotSet=Geen assembler set.
ErrorAssemblerNotSetAssumeDefault=Assembler niet expliciet ingesteld, dus  {0} wordt aangenomen.
ErrorAutomaticStringEncoderIsMultibyte=Automatisch ingepakte encoderingen mogen alleen uit enkele bytes bestaan.
ErrorBaseMustByTwoEightSixteen=Moet van het 2-, 8- of 16-tallig stelsel zijn.
ErrorBracketExpected=Deze token is geen haakje openen of haakje sluiten.
ErrorBracketMismatch=Haakjes vormen geen paar.
ErrorBracketNotClosed=Bijbehorend haakje sluiten niet gevonden.
ErrorBracketStartIndexOutOfBounds=Invalide index voor haakje openen.
ErrorCancellingBuild={0} error(s) gevonden: Bouwen wordt geannuleerd.
ErrorDirectiveNotDeclared=Directief '{0}' is onbekend.
ErrorEnvironmentNotSetTemplates=Omgevingsvariable Brass.Templates is niet ingesteld.
ErrorEvaluationAccessorLabelNotFound=Geen label gevonden voor label access operator.
ErrorEvaluationAssignmentsNotPermitted=Je kunt geen toekenningen doen in deze uitdrukking.
ErrorEvaluationExpectedFieldAccess=Veld toegang verwacht.
ErrorEvaluationExpectedOperandAfterOperator=Operand verwacht na operator.
ErrorEvaluationExpectedOperandBeforeOperator=Operand verwacht voor operator.
ErrorEvaluationFunctionNotDeclared=Functie '{0}' is onbekend.
ErrorEvaluationMissingConditionalOperator=Bijbehorende conditionele operator '?' ontbreekt.
ErrorEvaluationNoSingleResult=Syntax error.
ErrorEvaluationNothingToEvaluate=Niets te evalueren.
ErrorEvaluationOperandsUnsupported={0} operanden worden niet ondersteund.
ErrorEvaluationTypeInformationMissing=Kon type informatie niet verkrijgen.
ErrorExpectedAssignment=Er moet een toekenning gedaan worden.
ErrorFieldNotDeclared=Veld '{0}' niet gedefiniëerd.
ErrorFlowControlDisabled=Flow control is tijdelijk uitgeschakeld.
ErrorLabelAlreadyDefined=Herhaalde label '{0}'.
ErrorLabelCannotParse=Kan '{0}' niet verwerken.
ErrorLabelCannotRemoveOutputCounter=Je kunt het voorgedefiniëerde output teller label niet verwijderen.
ErrorLabelCannotRemoveProgramCounter=Je kunt het voorgedefiniëerde programma teller label niet verwijderen.
ErrorLabelInvalidNameNumber=Ongeldige naam '{0}' (lijkt op een nummer).
ErrorLabelIsConstant=Label '{0}' is constant en kan niets aan toegewezen worden.
ErrorLabelNotFound=Label '{0}' niet gevonden.
ErrorLabelPageNotFound=Pagina waarde voor label '{0}' niet gevonden.
ErrorLabelReusableAlreadyExistsAtPosition=Er bestaat op deze positie al een herbruikbare label.
ErrorLabelReusableInvalidClass='{0}' is geen geldige herbruikbare label klasse.
ErrorLabelReusableInvalidName=Ongeldige herbruikbare label naam.
ErrorLabelReusableNotFound=Kan waarde voor herbruikbare label '{0}' niet krijgen.
ErrorMacroAlreadyDefined=Macro {0} al gedefiniëerd.
ErrorModuleAlreadyAtTopLevel=Reeds in het bovenste module niveau.
ErrorOnlyLoadDuringInitialPass=Je kunt een bestand alleen laden en compileren tijdens de eerste pass.
ErrorOutputFilenameNotSet=Output bestandsnaam niet gespecificeerd.
ErrorPluginAlreadyAliased=Plugin '{0}' al geladen.
ErrorPluginNotFound=Plugin '{0}' niet gevonden.
ErrorProjectInvalidBuildConfigurationComponent=Ongeldig bouwconfiguratie component '{0}'.
ErrorProjectTemplateNotFound=Kan template {0} niet laden.
ErrorTokenTypeToInstruction=Type kan alleen op TokenType.Instruction gezet worden door assembler plugins.
ErrorUnspecifiedName=Geen naam gespecificeerd.
WarningPluginLoadedTwice=Plugin '{0}' wordt dubbel geladen.
What do you mean by this one?
ErrorArgumentExpectedSingleTokenAndIndex=Couldn't extract a single token and index.
Extract in which sense?
http://clap.timendus.com/ - The Calculator Link Alternative Protocol
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

Wow, thanks :) I'll package this with the next release, if you don't mind? For the moment, you can drop this file into an "nl" subdirectory relative to Brass.exe and Brass should appear in Dutch (plugin error messages won't, however, sorry).

Code: Select all

Gebruik: Brass ProjectFile
Interactieve rekenmachine modus. Type exit om af te sluiten.

> 3+
Operand verwacht na operator.
3+
> _
Plugins can request various components from the source string, usually done by splitting the source by commas. One such component is a single token (usually a label name) and an index, so hello[2+4] should return "hello" as the single token and an expression "2+4" as the index. (The related function is TokenisedSource.GetExpressionTokenAndIndex, as documented in Brass.chm).

Quite a few of the above errors are internal only and poorly phrased, my mistake.

I intend on releasing all of the source code with the next release, which might help a bit. :)
User avatar
Timendus
Calc King
Posts: 1729
Joined: Sun 23 Jan, 2005 12:37 am
Location: Netherlands
Contact:

Post by Timendus »

Well, if users will not usually have to deal with that error, I guess it's good enough this way :)

You're welcome, and I don't mind, but I'm still not convinced this is going to be of much use to anyone... ;)
http://clap.timendus.com/ - The Calculator Link Alternative Protocol
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

Timendus wrote:You're welcome, and I don't mind, but I'm still not convinced this is going to be of much use to anyone... ;)
I got badgered for a Dutch translation of Z80 Workshop years ago, so you never know. :D
CoBB
MCF Legend
Posts: 1601
Joined: Mon 20 Dec, 2004 8:45 am
Location: Budapest, Absurdistan
Contact:

Re: Brass Translation

Post by CoBB »

Nice idea. :) I’ve also switched to internationalisation-friendly programming lately. Still, I can’t help but notice something disturbing:
benryves wrote:

Code: Select all

...
ErrorArgumentCountMismatch=Expected {0} argument(s).
ErrorArgumentCountMismatchEndlessRange=Expected {0} or more arguments.
ErrorArgumentCountMismatchRange=Expected {0} to {1} argument(s).
...
ErrorCancellingBuild={0} error(s) found: Cancelling build.
...
Yes, the famous problem of plurals becomes much more of a pain (and that’s just the tip of the iceberg ;)) if you want to get it done properly.
User avatar
benryves
Maxcoderz Staff
Posts: 3087
Joined: Thu 16 Dec, 2004 10:06 pm
Location: Croydon, England
Contact:

Post by benryves »

The hard-coded string literals approach contained logic to handle singulars and plurals in English, but I've removed all that for the moment and just have the improper (but simpler) "noun(s)" form.

I take it you're saying that other languages will not have a "noun(s)" form? (I notice Timendus has used "argument(en)").
King Harold
Calc King
Posts: 1513
Joined: Sat 05 Aug, 2006 7:22 am

Post by King Harold »

That's because Dutch is quite close to English and has 2 forms (single/more) unlike weird Slavic languages with 4 forms (omg?)
<bad idea>
test for 4 forms but set them to only 2 different strings for english and dutch?
</bad idea>
CoBB
MCF Legend
Posts: 1601
Joined: Mon 20 Dec, 2004 8:45 am
Location: Budapest, Absurdistan
Contact:

Post by CoBB »

benryves wrote:I take it you're saying that other languages will not have a "noun(s)" form? (I notice Timendus has used "argument(en)").
Exactly, because it doesn’t make sense. And numbers might need to be declined too in some cases, but that’s another, even more horrible story. ;)
King Harold wrote:test for 4 forms but set them to only 2 different strings for english and dutch?
It doesn’t work, because the rules are different. For instance, in Russian numbers ending in 01, 21, 31...91 (but not 11!), including 1 itself require the same forms, which would break English.
King Harold
Calc King
Posts: 1513
Joined: Sat 05 Aug, 2006 7:22 am

Post by King Harold »

I did mention it was a bad idea, and it will work for more languages than if it would be split in 2 cases right?
User avatar
Timendus
Calc King
Posts: 1729
Joined: Sun 23 Jan, 2005 12:37 am
Location: Netherlands
Contact:

Post by Timendus »

I wouldn't argue that English is close to Dutch, but as you may have noticed I was able to translate many sentences almost literally, leaving a lot of English words in place even. But that has a lot to do with the fact that most of the tech-speak in Dutch is in fact English, not with how similar the two languages are.

Plurals in Dutch can end with "en" or with "s", but in a case like this I'd say you just make do with what you've got, as long as it's clear to the reader. Heck, it's an assembler with only a few lines of output text, why throw a big i18n library at that?
http://clap.timendus.com/ - The Calculator Link Alternative Protocol
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
CoBB
MCF Legend
Posts: 1601
Joined: Mon 20 Dec, 2004 8:45 am
Location: Budapest, Absurdistan
Contact:

Post by CoBB »

Timendus wrote:Plurals in Dutch can end with "en" or with "s", but in a case like this I'd say you just make do with what you've got, as long as it's clear to the reader. Heck, it's an assembler with only a few lines of output text, why throw a big i18n library at that?
Of course this issue couldn’t be farther from being critical in this case. ;) However, it’s good to be aware of such problems for future reference in order not to do it the wrong way. One of the right ways is using ngettext for instance.
Post Reply