<div id="__MailbirdStyleContent" style="font-size: 10pt;font-family: Arial;color: #000000;text-align: left" dir="ltr">
                                        Hi Christoph --<div><br></div><div>> <span style="font-family: Arial, Helvetica, sans-serif;font-size: 13px">I'm actually still not yet convinced by this pattern. :-)</span></div><div><span style="font-family: Arial, Helvetica, sans-serif;font-size: 13px"><br></span></div><div><span style="font-family: Arial, Helvetica, sans-serif;font-size: 13px">It's the only way to extract the phrases we want to translate. We MUST always send #translated or #translatedNoop to literals. Any message send in between could (and in this case would) modify the string (literal) and thus render any database lookup void.</span></div><div><span style="font-family: Arial, Helvetica, sans-serif;font-size: 13px"><br></span></div><div><span style="font-family: Arial, Helvetica, sans-serif"><span style="font-size: 13px">Consequently, this is not a matter of taste, but technical feasibility. We have currently no other way to extract strings from the image in a meaningful way. It's not about the translators. Just about the parser that extract the strings from the source code.</span></span></div><div><span style="font-family: Arial, Helvetica, sans-serif;font-size: 13px"><br></span></div><div><span style="font-family: Arial, Helvetica, sans-serif;font-size: 13px">Best,</span></div><div><span style="font-family: Arial, Helvetica, sans-serif;font-size: 13px">Marcel</span></div><div class="mb_sig"></div>
                                        <blockquote class="history_container" type="cite" style="border-left-style: solid;border-width: 1px;margin-top: 20px;margin-left: 0px;padding-left: 10px;min-width: 500px">
                        <p style="color: #AAAAAA; margin-top: 10px;">Am 07.02.2022 17:39:44 schrieb christoph.thiede@student.hpi.uni-potsdam.de <christoph.thiede@student.hpi.uni-potsdam.de>:</p><div style="font-family:Arial,Helvetica,sans-serif">
Hi Marcel,<br>
<br>
> Fixes GetText export: "withCRs translated" -> "translated withCRs"<br>
<br>
I'm actually still not yet convinced by this pattern. :-)<br>
<br>
"withCRs" is just one of many possible representation of strings in the image. "asTextFromHtml" or "asTextFromMarkdown" (yet to be implemented) would be two other alternative representations. I don't see why we should bother any translating persons with these artifacts (backslashes, HTML tags, or anything else) instead of just displaying the final object in the translator tool (that is, "Here is a line<br>
break" instead of "Here is a line\break" etc.).<br>
<br>
The only point I see is that the text export would not work well if we were sending #translated to any complex expressions rather than directly to a string literal. But surely it should be possible to detect the pattern "withCRs translated" during the export as well? What am I missing here? :-)<br>
<br>
Best,<br>
Christoph<br>
<br>
<span style="color: #808080">---<br>
</span><span style="color: #808080"><i>Sent from </i></span><span style="color: #808080"><i><a href="https://github.com/hpi-swa-lab/squeak-inbox-talk"><u><span style="color: #808080">Squeak Inbox Talk</span></u></a></i></span><br>
<br>
On 2022-01-19T10:47:16+00:00, commits@source.squeak.org wrote:<br>
<br>
> Marcel Taeumel uploaded a new version of Tools to project The Trunk:<br>
> http://source.squeak.org/trunk/Tools-mt.1108.mcz<br>
> <br>
> ==================== Summary ====================<br>
> <br>
> Name: Tools-mt.1108<br>
> Author: mt<br>
> Time: 19 January 2022, 11:47:15.336855 am<br>
> UUID: 0765184b-16e8-bf47-97b0-e8cc76adf54e<br>
> Ancestors: Tools-mt.1107<br>
> <br>
> Fixes GetText export: "withCRs translated" -> "translated withCRs"<br>
> <br>
> =============== Diff against Tools-mt.1107 ===============<br>
> <br>
> Item was changed:<br>
>   ----- Method: ChangeList>>contents: (in category 'viewing access') -----<br>
>   contents: aString<br>
>       listIndex = 0 ifTrue: [self changed: #flash. ^ false].<br>
>       lostMethodPointer ifNotNil: [^ self restoreDeletedMethod].<br>
>       self okToChange "means not dirty" ifFalse: ["is dirty"<br>
> +         self inform: 'This is a view of a method on a file.\Please cancel your changes.  You may\accept, but only when the method is untouched.' translated withCRs.  ^ false].<br>
> -         self inform: 'This is a view of a method on a file.\Please cancel your changes.  You may\accept, but only when the method is untouched.' withCRs translated.  ^ false].<br>
>           "Can't accept changes here.  Method text must be unchanged!!"<br>
>       (changeList at: listIndex) fileIn.<br>
>       ^ true!<br>
> <br>
> Item was changed:<br>
>   ----- Method: ChangeList>>selectSuchThat (in category 'menu actions') -----<br>
>   selectSuchThat<br>
>       "query the user for a selection criterio.  By Lex Spoon.  NB: the UI for invoking this from a changelist browser is currently commented out; to reenfranchise it, you'll need to mild editing to ChangeList method #changeListMenu:"<br>
>       | code block |<br>
> +     code := Project uiManager request: ('selection criteria for a change named aChangeRecord?\For instance, "{1}"' translated withCRs format: {'aChangeRecord category = ''System-Network'''}).<br>
> -     code := Project uiManager request: ('selection criteria for a change named aChangeRecord?\For instance, "{1}"' withCRs translated format: {'aChangeRecord category = ''System-Network'''}).<br>
>   <br>
>       code isEmpty ifTrue: [^ self ].<br>
>   <br>
>       block := Compiler evaluate: '[:aChangeRecord | ', code, ']'.<br>
>   <br>
>       self selectSuchThat: block!<br>
> <br>
> Item was changed:<br>
>   ----- Method: ChangeSorter class>>browseChangeSetsWithClass:selector: (in category 'browse') -----<br>
>   browseChangeSetsWithClass: class selector: selector<br>
>       "Put up a menu comprising a list of change sets that hold changes for the given class and selector.  If the user selects one, open a single change-sorter onto it"<br>
>   <br>
>       | hits index |<br>
>       hits := ChangeSet allChangeSets select: <br>
>           [:cs | (cs atSelector: selector class: class) ~~ #none].<br>
> +     hits isEmpty ifTrue: [^ self inform: ('{1}\is not in any change set' translated withCRs format: {class name, ' >> #', selector})].<br>
> -     hits isEmpty ifTrue: [^ self inform: ('{1}\is not in any change set' withCRs translated format: {class name, ' >> #', selector})].<br>
>       index := hits size = 1<br>
>           ifTrue:    [1]<br>
>           ifFalse:    [(Project uiManager chooseFrom: (hits collect: [:cs | cs name])<br>
>                       lines: #())].<br>
>       index = 0 ifTrue: [^ self].<br>
>       (ChangeSorter new myChangeSet: (hits at: index)) open.<br>
>   !<br>
> <br>
> Item was changed:<br>
>   ----- Method: ChangeSorter class>>browseChangeSetsWithSelector: (in category 'browse') -----<br>
>   browseChangeSetsWithSelector: aSelector<br>
>       "Put up a list of all change sets that contain an addition, deletion, or change of any method with the given selector"<br>
>   <br>
>       | hits index |<br>
>       hits := ChangeSet allChangeSets select: <br>
>           [:cs | cs hasAnyChangeForSelector: aSelector].<br>
> +     hits isEmpty ifTrue: [^ self inform: ('{1}\is not in any change set' translated withCRs format: {aSelector})].<br>
> -     hits isEmpty ifTrue: [^ self inform: ('{1}\is not in any change set' withCRs translated format: {aSelector})].<br>
>       index := hits size = 1<br>
>           ifTrue:    [1]<br>
>           ifFalse:    [(Project uiManager chooseFrom: (hits collect: [:cs | cs name])<br>
>                       lines: #())].<br>
>       index = 0 ifTrue: [^ self].<br>
>       (ChangeSetBrowser new myChangeSet: (hits at: index)) open<br>
>   <br>
>   "ChangeSorter browseChangeSetsWithSelector: #clearPenTrails"<br>
>   !<br>
> <br>
> Item was changed:<br>
>   ----- Method: ChangeSorter>>clearChangeSet (in category 'changeSet menu') -----<br>
>   clearChangeSet<br>
>       "Clear out the current change set, after getting a confirmation."<br>
>       | message |<br>
>   <br>
>       self okToChange ifFalse: [^ self].<br>
>       myChangeSet isEmpty ifFalse:<br>
> +         [message := 'Are you certain that you want to\forget all the changes in this set?' translated withCRs.<br>
> -         [message := 'Are you certain that you want to\forget all the changes in this set?' withCRs translated.<br>
>           (self confirm: message) ifFalse: [^ self]].<br>
>       myChangeSet clear.<br>
>       self changed: #classList.<br>
>       self changed: #messageList.<br>
>       self setContents.<br>
>       self contentsChanged.<br>
>   !<br>
> <br>
> Item was changed:<br>
>   ----- Method: Debugger>>contents:notifying: (in category 'accessing') -----<br>
>   contents: aText notifying: aController<br>
>       "Accept new method source of the selected context."<br>
>   <br>
>       | selector classOfMethod category ctxt newMethod |<br>
>       contextStackIndex = 0 ifTrue: [^ false].<br>
>       <br>
>       "First, handle some edge cases"<br>
>       selector := self selectedClass newParser parseSelector: aText.<br>
>       "selector isDoIt ifTrue: [<br>
>           currentCompiledMethod := self compileDoIt: aText]."<br>
>       self flag: #todo. "ct: Recompile doIt method *without* creating method litters!! See Compiler>>#evaluateCue:ifFail:."<br>
>       selector = self selectedMessageName ifFalse: [<br>
>           "Different message compiled, delegating to super"<br>
>           ^ super contents: aText notifying: aController].<br>
>       <br>
>       self selectedContext isExecutingBlock ifTrue: [<br>
>           "If we are in a block context, we need to rewind the stack before ."<br>
>           | home |<br>
>           home := self selectedContext activeHome.<br>
>           home ifNil: [<br>
>               self inform: 'Method for block not found on stack, can''t edit and continue' translated.<br>
>               ^ false].<br>
> +         (self confirm: 'I will have to revert to the method from\which this block originated. Is that OK?' translated withCRs) ifFalse: [<br>
> -         (self confirm: 'I will have to revert to the method from\which this block originated. Is that OK?' withCRs translated) ifFalse: [<br>
>               ^ false].<br>
>           <br>
>           self resetContext: home changeContents: false.<br>
>           "N.B. Only reset the contents if the compilation succeeds. If contents would be reset when compilation fails, both compiler error message and modifications were lost."<br>
>           ^ (self contents: aText notifying: aController)<br>
>               ifTrue: [self contentsChanged];<br>
>               yourself].<br>
>       <br>
>       classOfMethod := self selectedClass.<br>
>       category := self selectedMessageCategoryName.<br>
>       <br>
>       "Do the actual compilation"<br>
>       selector := classOfMethod<br>
>           compile: aText<br>
>           classified: category<br>
>           notifying: aController.<br>
>       selector ifNil: [^ false]. "compilation cancelled"<br>
>       <br>
>       "Update views"<br>
>       contents := aText.<br>
>       newMethod := classOfMethod compiledMethodAt: selector.<br>
>       newMethod isQuick ifTrue: [<br>
>           self cutBackExecutionToSenderContext].<br>
>       ctxt := interruptedProcess popTo: self selectedContext.<br>
>       ctxt == self selectedContext<br>
> +         ifFalse: [self inform: 'Method saved, but current context unchanged\because of unwind error. Click OK to see error' translated withCRs]<br>
> -         ifFalse: [self inform: 'Method saved, but current context unchanged\because of unwind error. Click OK to see error' withCRs translated]<br>
>           ifTrue: [<br>
>               newMethod isQuick ifFalse: [<br>
>                   interruptedProcess restartTopWith: newMethod.<br>
>                   interruptedProcess stepToSendOrReturn].<br>
>               contextVariablesInspector object: nil].<br>
>       self resetContext: ctxt.<br>
>       <br>
>       Project current addDeferredUIMessage: [<br>
>           self changed: #contentsSelection].<br>
>       ^ true!<br>
> <br>
> Item was changed:<br>
>   ----- Method: StandardToolSet class>>debugProcess:context:label:contents:fullView: (in category 'debugging') -----<br>
>   debugProcess: aProcess context: aContext label: aString contents: contents fullView: aBool<br>
>   <br>
>       (aProcess isTerminated and: [aString isNil or: [aString beginsWith: 'Debug it']]) ifTrue: [<br>
> +         ^ Project uiManager inform: 'Nothing to debug. Process has terminated.\Expression optimized.' translated withCRs].<br>
> -         ^ Project uiManager inform: 'Nothing to debug. Process has terminated.\Expression optimized.' withCRs translated].<br>
>   <br>
>       ^ Debugger<br>
>           openOn: aProcess<br>
>           context: aContext<br>
>           label: aString<br>
>           contents: contents<br>
>           fullView: aBool!<br>
> <br>
> Item was changed:<br>
>   ----- Method: StandardToolSet class>>handleWarning: (in category 'debugging - handlers') -----<br>
>   handleWarning: aWarning<br>
>       "Double dispatch. Let the processor take care of that warning, which usually calls back here to #debugProcess:..."<br>
>   <br>
>       | message |<br>
>       message := '{1}\\{2}' withCRs asText format: {<br>
>           "First, show the actual text of this warning."<br>
>           aWarning messageText.<br>
>           "Second, append some helpful information that apply to all kinds of warnings."<br>
>           ('{1} {2}' asText format: {<br>
>               'Select "Proceed" to continue or close this window to cancel the operation.' translated.<br>
>               'If you do not want to be interrupted anymore, you can {1} this kind of warning. You can also {2}, which resets such warnings on the next image startup.' translated asText format: {<br>
>                   "Provide clickable text links so that the user can directly suppress warnings."<br>
>                   'always suppress' asText<br>
>                       addAttribute: (PluggableTextAttribute evalBlock: [<br>
>                           aWarning class suppressWarnings.<br>
>                           self inform: ('All ''{1}'' warnings will be suppressed.' translated format: {aWarning class name})]).<br>
>                   'suppress temporarily' asText<br>
>                       addAttribute: (PluggableTextAttribute evalBlock: [<br>
>                           aWarning class suppressAndResetOnStartUp.<br>
> +                         self inform: ('All ''{1}'' warnings will be suppressed\and reset on the next image startup.' translated withCRs format: {aWarning class name})])}.<br>
> -                         self inform: ('All ''{1}'' warnings will be suppressed\and reset on the next image startup.' withCRs translated format: {aWarning class name})])}.<br>
>               }) addAttribute: (<br>
>                   "Show this helpful information in a smaller font."<br>
>                   TextFontReference toFont: Preferences standardButtonFont)}.<br>
>       <br>
>       ^ Processor<br>
>           debugContext: aWarning signalerContext<br>
>           title: 'Warning' translated<br>
>           full: false<br>
>           contents: message!<br>
> <br>
> Item was changed:<br>
>   ----- Method: Workspace>>appendContentsToFileOnAccept (in category 'menu commands') -----<br>
>   appendContentsToFileOnAccept<br>
>       "Arrange that the contents will be appended to a file when the user accepts."<br>
>   <br>
>       self saveContentsInFileOnAcceptEnabled<br>
> +         ifTrue: [(Project uiManager confirm: 'Do you really want to change file access mode\from #update to #append?\\You might corrupt data when accepting changes.' translated withCRs)<br>
> -         ifTrue: [(Project uiManager confirm: 'Do you really want to change file access mode\from #update to #append?\\You might corrupt data when accepting changes.' withCRs translated)<br>
>               ifFalse: [^ self]].<br>
>   <br>
>       self acceptAction: (self appendContentsToFileOnAcceptEnabled ifTrue: [ "no action" ] ifFalse: [<br>
>           [:freshContents | | fileName stringToAppend |<br>
>               "Ensure to compute fileName as late as possible to consider recent changes of the #windowTitle."<br>
>               fileName := self suggestedFileNameForSave.<br>
>               <br>
>               stringToAppend := '"----ACCEPT----{1}"\{2}\' withCRs<br>
>                   format: { DateAndTime now asString. freshContents }.<br>
>               <br>
>               ((FileDirectory forFileName: fileName) fileExists: fileName)<br>
>                   ifFalse: [ "If the default file name, which is derived from the current window title, does not exist, ask the user once to confirm the location."        <br>
>                       self<br>
>                           saveContents: stringToAppend<br>
>                           accessMode: #create]<br>
>                   ifTrue: [ "Update/replace the contents in the existing file."<br>
>                       self<br>
>                           saveContents: stringToAppend<br>
>                           onFileNamed: fileName<br>
>                           accessMode: #append]] ]).!<br>
> <br>
> Item was changed:<br>
>   ----- Method: Workspace>>saveContentsInFileOnAccept (in category 'menu commands') -----<br>
>   saveContentsInFileOnAccept<br>
>       "Arrange that the contents will be saved to a file on each save (or accept). Replace any existing file contents."<br>
>   <br>
>       self flag: #discuss. "mt: Is it 'onFile' or rather 'inFile'? Note that there are different access modes."<br>
>   <br>
>       self appendContentsToFileOnAcceptEnabled<br>
> +         ifTrue: [(Project uiManager confirm: 'Do you really want to change file access mode\from #append to #update?\\You might lose data when accepting changes.' translated withCRs)<br>
> -         ifTrue: [(Project uiManager confirm: 'Do you really want to change file access mode\from #append to #update?\\You might lose data when accepting changes.' withCRs translated)<br>
>               ifFalse: [^ self]].<br>
>       <br>
>       self acceptAction: (self saveContentsInFileOnAcceptEnabled<br>
>           ifFalse: [ [:stringToSave | | fileName |<br>
>               "Ensure to compute fileName as late as possible to consider recent changes of the #windowTitle."<br>
>               fileName := self suggestedFileNameForSave.<br>
>               <br>
>               ((FileDirectory forFileName: fileName) fileExists: fileName)<br>
>                   ifFalse: [ "If the default file name, which is derived from the current window title, does not exist, ask the user once to confirm the location."        <br>
>                       self<br>
>                           saveContents: stringToSave<br>
>                           accessMode: #create]<br>
>                   ifTrue: [ "Update/replace the contents in the existing file."<br>
>                       self<br>
>                           saveContents: stringToSave<br>
>                           onFileNamed: fileName<br>
>                           accessMode: #update]] ]).!<br>
> <br>

</div></blockquote></div>