--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Tools__InternationalLanguageTranslationEditor.st Mon Mar 06 09:26:48 2006 +0100
@@ -0,0 +1,1330 @@
+"{ Package: 'stx:libtool2' }"
+
+"{ NameSpace: Tools }"
+
+ApplicationModel subclass:#InternationalLanguageTranslationEditor
+ instanceVariableNames:'languagesList keyStringsToLanguageMappings languageTextHolder
+ originalTextHolder modified shownLanguages selectedKeyRow
+ showMissingTranslationsOnly
+ keyStringAndLanguageSelectionTableColumnDescriptionHolder
+ languageShownHolders dataSetView lastExtractedClass
+ lastExtractedApplicationClass stopApplicationIconVisibleHolder
+ monitoredApplication originalTextModifiedHolder
+ languageTextModifiedHolder'
+ classVariableNames:'LastExtractedClass LastExtractedApplicationClass'
+ poolDictionaries:''
+ category:'Interface-UIPainter'
+!
+
+Object subclass:#AccessCollectingPseudoResourcePack
+ instanceVariableNames:'collectedKeys realResourcePack'
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:InternationalLanguageTranslationEditor
+!
+
+Collection subclass:#KeyStringsToLanguageMappings
+ instanceVariableNames:'keys languageMappings languages'
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:InternationalLanguageTranslationEditor
+!
+
+Object subclass:#LanguageMappingRow
+ instanceVariableNames:'key mappings'
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:InternationalLanguageTranslationEditor
+!
+
+Visitor subclass:#UISpecVisitor
+ instanceVariableNames:'translatedLabels'
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:InternationalLanguageTranslationEditor
+!
+
+!InternationalLanguageTranslationEditor class methodsFor:'documentation'!
+
+documentation
+"
+ documentation to be added.
+
+ [author:]
+ cg (cg@FUSI)
+
+ [instance variables:]
+
+ [class variables:]
+
+ [see also:]
+
+"
+!
+
+examples
+"
+ Starting the application:
+ [exBegin]
+ InternationalLanguageTranslationEditor open
+
+ [exEnd]
+
+ more examples to be added:
+ [exBegin]
+ ... add code fragment for
+ ... executable example here ...
+ [exEnd]
+"
+!
+
+history
+ "Created: / 04-03-2006 / 09:07:19 / cg"
+! !
+
+!InternationalLanguageTranslationEditor class methodsFor:'interface specs'!
+
+windowSpec
+ "This resource specification was automatically generated
+ by the UIPainter of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the UIPainter may not be able to read the specification."
+
+ "
+ UIPainter new openOnClass:InternationalLanguageTranslationEditor andSelector:#windowSpec
+ InternationalLanguageTranslationEditor new openInterface:#windowSpec
+ InternationalLanguageTranslationEditor open
+ "
+
+ <resource: #canvas>
+
+ ^
+ #(FullSpec
+ name: windowSpec
+ window:
+ (WindowSpec
+ label: 'InternationalLanguageTranslationEditor'
+ name: 'InternationalLanguageTranslationEditor'
+ min: (Point 10 10)
+ max: (Point 1024 768)
+ bounds: (Rectangle 0 0 640 400)
+ menu: mainMenu
+ )
+ component:
+ (SpecCollection
+ collection: (
+ (MenuPanelSpec
+ name: 'ToolBar'
+ layout: (LayoutFrame 0 0 0 0 0 1 30 0)
+ menu: menuToolBar
+ textDefault: true
+ )
+ (VariableVerticalPanelSpec
+ name: 'VariableVerticalPanel1'
+ layout: (LayoutFrame 0 0 30 0 0 1 0 1)
+ component:
+ (SpecCollection
+ collection: (
+ (DataSetSpec
+ name: 'KeyStringAndLanguageSelectionTable'
+ model: selectedKeyRow
+ hasHorizontalScrollBar: true
+ hasVerticalScrollBar: true
+ dataList: keyStringAndLanguageSelectionTable
+ columnHolder: keyStringAndLanguageSelectionTableColumnDescriptionHolder
+ columnAdaptor: yourself
+ postBuildCallback: postBuildDataSet:
+ )
+ (ViewSpec
+ name: 'Box1'
+ component:
+ (SpecCollection
+ collection: (
+ (LabelSpec
+ label: 'Original String (Key):'
+ name: 'Label2'
+ layout: (LayoutFrame 0 0 0 0 0 1 30 0)
+ translateLabel: true
+ adjust: left
+ )
+ (TextEditorSpec
+ name: 'OriginalText'
+ layout: (LayoutFrame 0 0 30 0 0 1 0 1)
+ model: originalTextHolder
+ hasHorizontalScrollBar: true
+ hasVerticalScrollBar: true
+ modifiedChannel: originalTextModifiedHolder
+ )
+ )
+
+ )
+ )
+ (ViewSpec
+ name: 'Box2'
+ component:
+ (SpecCollection
+ collection: (
+ (LabelSpec
+ label: 'Translated String:'
+ name: 'Label1'
+ layout: (LayoutFrame 0 0 0 0 0 1 30 0)
+ translateLabel: true
+ adjust: left
+ )
+ (TextEditorSpec
+ name: 'LanguageText'
+ layout: (LayoutFrame 0 0 30 0 0 1 0 1)
+ model: languageTextHolder
+ hasHorizontalScrollBar: true
+ hasVerticalScrollBar: true
+ modifiedChannel: languageTextModifiedHolder
+ )
+ )
+
+ )
+ )
+ )
+
+ )
+ handles: (Any 0.33333333333333 0.66666666666667 1.0)
+ )
+ )
+
+ )
+ )
+! !
+
+!InternationalLanguageTranslationEditor class methodsFor:'menu specs'!
+
+mainMenu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:InternationalLanguageTranslationEditor andSelector:#mainMenu
+ (Menu new fromLiteralArrayEncoding:(InternationalLanguageTranslationEditor mainMenu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(Menu
+ (
+ (MenuItem
+ label: 'File'
+ translateLabel: true
+ submenu:
+ (Menu
+ (
+ (MenuItem
+ label: 'New'
+ itemValue: menuNew
+ translateLabel: true
+ )
+ (MenuItem
+ label: '-'
+ )
+ (MenuItem
+ label: 'Open Resource File...'
+ itemValue: menuOpen
+ translateLabel: true
+ )
+ (MenuItem
+ label: '-'
+ )
+ (MenuItem
+ label: 'Save Resource File'
+ itemValue: menuSave
+ translateLabel: true
+ )
+ (MenuItem
+ label: 'Save Resource File As...'
+ itemValue: menuSaveAs
+ translateLabel: true
+ )
+ (MenuItem
+ label: '-'
+ )
+ (MenuItem
+ label: 'Exit'
+ itemValue: closeRequest
+ translateLabel: true
+ )
+ )
+ nil
+ nil
+ )
+ )
+ (MenuItem
+ label: 'View'
+ translateLabel: true
+ submenu:
+ (Menu
+ (
+ (MenuItem
+ label: 'Show Missing Translations Only'
+ translateLabel: true
+ indication: showMissingTranslationsOnly
+ )
+ (MenuItem
+ label: '-'
+ )
+ (MenuItem
+ label: 'Shown Languages'
+ translateLabel: true
+ submenuChannel: shownLanguagesMenu
+ )
+ )
+ nil
+ nil
+ )
+ )
+ (MenuItem
+ label: 'Languages'
+ translateLabel: true
+ submenu:
+ (Menu
+ (
+ (MenuItem
+ label: 'Add Language...'
+ itemValue: addLanguage
+ translateLabel: true
+ )
+ (MenuItem
+ label: 'Remove Language...'
+ itemValue: removeLanguage
+ translateLabel: true
+ )
+ )
+ nil
+ nil
+ )
+ )
+ (MenuItem
+ label: 'Translations'
+ translateLabel: true
+ submenu:
+ (Menu
+ (
+ (MenuItem
+ label: 'Add Translation...'
+ itemValue: addTranslation
+ translateLabel: true
+ )
+ (MenuItem
+ label: 'Remove Translation...'
+ itemValue: removeTranslation
+ translateLabel: true
+ )
+ (MenuItem
+ label: '-'
+ )
+ (MenuItem
+ label: 'Extract from Class...'
+ itemValue: extractTranslationsFromClass
+ translateLabel: true
+ )
+ (MenuItem
+ label: 'Run Application and Collect Translations...'
+ itemValue: runApplicationAndCollectTranslations
+ translateLabel: true
+ )
+ )
+ nil
+ nil
+ )
+ )
+ (MenuItem
+ label: 'Help'
+ translateLabel: true
+ startGroup: right
+ submenu:
+ (Menu
+ (
+ (MenuItem
+ label: 'Documentation'
+ itemValue: openDocumentation
+ translateLabel: true
+ )
+ (MenuItem
+ label: '-'
+ )
+ (MenuItem
+ label: 'About this Application...'
+ itemValue: openAboutThisApplication
+ translateLabel: true
+ )
+ )
+ nil
+ nil
+ )
+ )
+ )
+ nil
+ nil
+ )
+!
+
+menuToolBar
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:InternationalLanguageTranslationEditor andSelector:#menuToolBar
+ (Menu new fromLiteralArrayEncoding:(InternationalLanguageTranslationEditor menuToolBar)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(Menu
+ (
+ (MenuItem
+ label: 'Save'
+ translateLabel: true
+ labelImage: (ResourceRetriever XPToolbarIconLibrary saveImageIcon)
+ )
+ (MenuItem
+ label: '-'
+ )
+ (MenuItem
+ label: 'Add Translation'
+ itemValue: addTranslation
+ translateLabel: true
+ labelImage: (ResourceRetriever XPToolbarIconLibrary newRowIcon)
+ )
+ (MenuItem
+ label: 'Remove Translation'
+ itemValue: removeTranslation
+ translateLabel: true
+ labelImage: (ResourceRetriever XPToolbarIconLibrary removeRowIcon)
+ )
+ (MenuItem
+ label: ''
+ )
+ (MenuItem
+ label: 'Stop Application'
+ itemValue: stopApplication
+ translateLabel: true
+ isVisible: stopApplicationIconVisibleHolder
+ labelImage: (ResourceRetriever XPToolbarIconLibrary stop16x16Icon)
+ )
+ )
+ nil
+ nil
+ )
+! !
+
+!InternationalLanguageTranslationEditor methodsFor:'aspects'!
+
+keyStringAndLanguageSelectionTable
+ keyStringsToLanguageMappings isNil ifTrue:[
+ keyStringsToLanguageMappings := KeyStringsToLanguageMappings new.
+ ].
+ ^ keyStringsToLanguageMappings.
+!
+
+keyStringAndLanguageSelectionTableColumnDescriptionHolder
+ keyStringAndLanguageSelectionTableColumnDescriptionHolder isNil ifTrue:[
+ keyStringAndLanguageSelectionTableColumnDescriptionHolder := ValueHolder new.
+ keyStringAndLanguageSelectionTableColumnDescriptionHolder value:(self keyStringAndLanguageSelectionTableColumnDescription).
+ ].
+ ^ keyStringAndLanguageSelectionTableColumnDescriptionHolder.
+!
+
+languageAtCol:colNr
+ ^ shownLanguages at:colNr-1.
+!
+
+languageShownHolderFor:lang
+ |holder|
+
+ languageShownHolders isNil ifTrue:[
+ languageShownHolders := Dictionary new
+ ].
+ holder := languageShownHolders
+ at:lang
+ ifAbsentPut:[
+ |h|
+
+ h := true asValue.
+ h onChangeEvaluate:[
+ h value ifTrue:[
+ self enableLanguageDisplayFor:lang
+ ] ifFalse:[
+ self disableLanguageDisplayFor:lang
+ ].
+ ].
+ h
+ ].
+ ^ holder.
+!
+
+languageTextHolder
+ languageTextHolder isNil ifTrue:[
+ languageTextHolder := '' asValue.
+ ].
+ ^ languageTextHolder.
+!
+
+languageTextModifiedHolder
+ languageTextModifiedHolder isNil ifTrue:[
+ languageTextModifiedHolder := false asValue.
+ ].
+ ^ languageTextModifiedHolder.
+!
+
+languagesList
+ languagesList isNil ifTrue:[
+ languagesList := List withAll:(self keyStringAndLanguageSelectionTable languages).
+ ].
+ ^ languagesList.
+!
+
+originalTextHolder
+ originalTextHolder isNil ifTrue:[
+ originalTextHolder := '' asValue.
+ ].
+ ^ originalTextHolder.
+!
+
+originalTextModifiedHolder
+ originalTextModifiedHolder isNil ifTrue:[
+ originalTextModifiedHolder := false asValue.
+ ].
+ ^ originalTextModifiedHolder.
+!
+
+selectedKeyRow
+ selectedKeyRow isNil ifTrue:[
+ selectedKeyRow := ValueHolder new.
+ selectedKeyRow onChangeSend:#selectionChanged to:self.
+ ].
+ ^ selectedKeyRow.
+!
+
+showMissingTranslationsOnly
+ showMissingTranslationsOnly isNil ifTrue:[
+ showMissingTranslationsOnly := false asValue.
+ ].
+ ^ showMissingTranslationsOnly.
+!
+
+shownLanguages
+ shownLanguages isNil ifTrue:[
+ shownLanguages := List new.
+ shownLanguages addAll:(self languagesList).
+ shownLanguages onChangeSend:#shownLanguagesChanged to:self.
+ ].
+ ^ shownLanguages.
+!
+
+stopApplicationIconVisibleHolder
+ stopApplicationIconVisibleHolder isNil ifTrue:[
+ stopApplicationIconVisibleHolder := false asValue.
+ ].
+ ^ stopApplicationIconVisibleHolder.
+! !
+
+!InternationalLanguageTranslationEditor methodsFor:'initialization & release'!
+
+closeRequest
+ "asks for permission before closing"
+
+ self hasUnsavedChanges ifTrue:[
+ (Dialog
+ confirm:(resources string:'Close without saving ?')
+ default:false) ifFalse:[
+ ^ self
+ ]
+ ].
+
+ super closeRequest
+!
+
+initialize
+ modified := false.
+ super initialize
+!
+
+postBuildDataSet:aView
+ dataSetView := aView
+! !
+
+!InternationalLanguageTranslationEditor methodsFor:'menu actions'!
+
+addLanguage
+ |lang|
+
+ lang := Dialog request:'New language (ISO symbol):'.
+ lang isEmptyOrNil ifTrue:[^ self].
+
+ (keyStringsToLanguageMappings includesLanguage:lang) ifTrue:[^ self ].
+
+ keyStringsToLanguageMappings addLanguage:lang.
+ self languagesList add:lang.
+ self shownLanguages add:lang.
+ modified := true.
+!
+
+addTranslation
+ |key index|
+
+ key := Dialog request:'New Key:'.
+ (keyStringsToLanguageMappings includesKey:key) ifFalse:[
+ keyStringsToLanguageMappings addKey:key.
+ modified := true.
+ ].
+ index := keyStringsToLanguageMappings indexOfKey:key.
+
+ self selectedKeyRow value:index
+!
+
+extractTranslationsFromClass
+ |aClass newTranslations|
+
+ aClass := Dialog
+ requestClass:'Class to extract translations from:'
+ okLabel:'OK'
+ initialAnswer:(lastExtractedClass ? LastExtractedClass).
+ aClass isNil ifTrue:[^ self ].
+
+ lastExtractedClass := LastExtractedClass := aClass.
+
+ newTranslations := Set new.
+
+ self withWaitCursorDo:[
+ "/ now, the hard part:
+ "/ possible translations are in the specs,
+ "/ and all arguments to (resources string:) messages.
+ aClass instAndClassMethodsDo:[:eachMethod |
+ newTranslations addAll:( self extractTranslationsFromMethod:eachMethod ).
+ ].
+ ].
+
+ newTranslations := newTranslations select:[:k | k notEmpty and:[k isBlank not]].
+ newTranslations := newTranslations select:[:k | (keyStringsToLanguageMappings includesKey:k) not].
+ newTranslations notEmpty ifTrue:[
+ newTranslations := newTranslations asSortedCollection.
+ keyStringsToLanguageMappings addKeys:newTranslations.
+ modified := true.
+ ].
+!
+
+menuNew
+ modified ifTrue:[
+ (Dialog
+ confirm:(resources stringWithCRs:'Modified translations have not been changed.\\Create new translations set anyway ?')
+ default:false) ifFalse:[^ self].
+ ].
+
+ keyStringsToLanguageMappings initialize.
+ keyStringsToLanguageMappings changed.
+
+ self languagesList contents:self keyStringAndLanguageSelectionTable languages.
+ self shownLanguages contents:self keyStringAndLanguageSelectionTable languages.
+ modified := false.
+!
+
+menuOpen
+ |fn|
+
+ fn := Dialog
+ requestFileName:'Name of resource file:'
+ default:nil
+ pattern:'*.rs'.
+
+ fn isEmptyOrNil ifTrue:[^ self ].
+ fn := fn asFilename.
+ fn exists ifFalse:[^ self ].
+
+ self readResourceFile:fn
+!
+
+menuSave
+ "This method was generated by the Browser.
+ It will be invoked when the menu-item 'save' is selected."
+
+ "/ change below and add any actions as required here ...
+ self warn:'no action for ''save'' available.'.
+!
+
+menuSaveAs
+ "This method was generated by the Browser.
+ It will be invoked when the menu-item 'saveAs' is selected."
+
+ "/ change below and add any actions as required here ...
+ self warn:'no action for ''saveAs'' available.'.
+!
+
+openAboutThisApplication
+ "This method was generated by the Browser.
+ It will be invoked when the menu-item 'help-about' is selected."
+
+ "/ could open a customized aboutBox here ...
+ super openAboutThisApplication
+!
+
+openDocumentation
+ "This method was generated by the Browser.
+ It will be invoked when the menu-item 'help-documentation' is selected."
+
+ "/ change below as required ...
+
+ "/ to open an HTML viewer on some document (under 'doc/online/<language>/' ):
+ HTMLDocumentView openFullOnDocumentationFile:'TOP.html'.
+
+ "/ add application-specific help files under the 'doc/online/<language>/help/appName'
+ "/ directory, and open a viewer with:
+ "/ HTMLDocumentView openFullOnDocumentationFile:'help/<MyApplication>/TOP.html'.
+!
+
+readResourceFile:aFilename
+ |inStream lineString|
+
+ aFilename exists ifFalse:[^ self ].
+
+ inStream := aFilename readStream.
+ [inStream atEnd] whileFalse:[
+ lineString := inStream nextLine.
+ (lineString notEmpty
+ and:[ (lineString startsWith:';') not ]) ifTrue:[
+ (lineString startsWith:'#encoding ') ifTrue:[
+self halt.
+ ] ifFalse:[
+self halt.
+ ].
+ ].
+ ].
+ inStream close.
+!
+
+removeLanguage
+ "automatically generated by UIEditor ..."
+
+ "*** the code below performs no action"
+ "*** (except for some feedback on the Transcript)"
+ "*** Please change as required and accept in the browser."
+ "*** (and replace this comment by something more useful ;-)"
+
+ "action to be added ..."
+
+ Transcript showCR:self class name, ': action for #removeLanguage ...'.
+!
+
+removeTranslation
+ |rowSelectionIndex selectedKey|
+
+ rowSelectionIndex := self selectedKeyRow value.
+ rowSelectionIndex ~~ 0 ifTrue:[
+ selectedKey := keyStringsToLanguageMappings keyAt:rowSelectionIndex ifAbsent:nil.
+ (Dialog confirm:(resources string:'Really remove key %1' with:selectedKey)) ifTrue:[
+ keyStringsToLanguageMappings removeKey:selectedKey.
+ ].
+ ].
+!
+
+runApplicationAndCollectTranslations
+ |applicationClass newTranslations pseudoPack app|
+
+ monitoredApplication notNil ifTrue:[
+ monitoredApplication terminate.
+ [monitoredApplication notNil] whileTrue:[
+ Delay waitForSeconds:0.1
+ ].
+ ].
+
+ applicationClass := Dialog
+ requestClass:'Application class to start and collect translations from:'
+ okLabel:'OK'
+ initialAnswer:(lastExtractedApplicationClass ? LastExtractedApplicationClass ).
+ applicationClass isNil ifTrue:[^ self ].
+
+ lastExtractedApplicationClass := LastExtractedApplicationClass := applicationClass.
+
+ newTranslations := Set new.
+
+ pseudoPack := AccessCollectingPseudoResourcePack new.
+ pseudoPack realResourcePack:(applicationClass classResources).
+
+ self stopApplicationIconVisibleHolder value:true.
+
+ monitoredApplication := [
+ [
+ app := applicationClass new.
+ app open.
+ app window waitUntilVisible.
+ app window waitUntilClosed.
+ ] ensure:[
+ app closeRequest.
+ self stopApplicationIconVisibleHolder value:false.
+ monitoredApplication := nil.
+ ].
+ ] fork.
+! !
+
+!InternationalLanguageTranslationEditor methodsFor:'menus dynamic'!
+
+disableLanguageDisplayFor:lang
+ self shownLanguages remove:lang ifAbsent:[]
+!
+
+enableLanguageDisplayFor:newLang
+ |shownLanguagesInOrder|
+
+ (self shownLanguages includes:newLang) ifFalse:[
+ shownLanguagesInOrder := self languagesList
+ select:[:lang | (self shownLanguages includes:lang)
+ or:[ lang = newLang ]].
+ self shownLanguages contents:shownLanguagesInOrder.
+ ]
+!
+
+isLanguageShown:lang
+ ^ self shownLanguages includes:lang
+!
+
+shownLanguagesMenu
+ <resource: #programMenu >
+
+ ^ [
+ |m selected|
+
+ m := Menu new.
+
+ self languagesList do:[:lang |
+ |item|
+
+ item := MenuItem label:lang.
+ item indication:(self languageShownHolderFor:lang).
+ item hideMenuOnActivated:false.
+ m addItem:item.
+ ].
+ m
+ ].
+!
+
+toggleLanguageDisplayFor:lang
+ (self shownLanguages includes:lang) ifTrue:[
+ self disableLanguageDisplayFor:lang
+ ] ifFalse:[
+ self enableLanguageDisplayFor:lang
+ ].
+! !
+
+!InternationalLanguageTranslationEditor methodsFor:'private-key extraction'!
+
+extractTranslationsFromHelpSpecMethod:aMethod
+ |codeStrings matcher parseTree resourceKeys|
+
+ parseTree := RBParser
+ parseMethod:aMethod source
+ onError: [:str :pos | Transcript showCR:str. Transcript showCR:pos.
+ nil].
+ parseTree isNil ifTrue:[^ #() ].
+
+ codeStrings :=
+ #(
+ '`@dict addPairsFrom: `#helpKeysAndStrings'
+ ).
+
+ resourceKeys := Set new.
+
+ matcher := ParseTreeSearcher new.
+ matcher
+ matchesAnyOf: codeStrings
+ do: [:aNode :answer |
+ |sel argNode arg|
+
+ sel := aNode selector.
+ (sel startsWith:'addPairsFrom:') ifTrue:[
+ argNode := aNode arguments at:1.
+ argNode isLiteral ifTrue:[
+ arg := argNode value.
+ arg isArray ifTrue:[
+ arg doWithIndex:[:el :index |
+ index even ifTrue:[
+ el isString ifTrue:[
+ resourceKeys add:el.
+ ]
+ ].
+ ].
+ ] ifFalse:[
+ Transcript
+ showCR:(resources
+ string:'Cannot derive resourceKey from non-array in %1 in %2'
+ with:argNode formattedCode
+ with:aMethod selector).
+ ].
+ ] ifFalse:[
+ Transcript
+ showCR:(resources
+ string:'Cannot derive resourceKey from non-literal: %1 in %2'
+ with:argNode formattedCode
+ with:aMethod selector).
+ ].
+ ].
+ aNode
+ ].
+
+ matcher executeTree: parseTree initialAnswer: nil.
+ ^ resourceKeys
+!
+
+extractTranslationsFromMenuSpecMethod:aMethod
+ |menu resourceKeys|
+
+ menu := aMethod mclass theNonMetaclass perform:aMethod selector.
+ menu isNil ifTrue:[ ^ #() ].
+
+ (menu isKindOf:Menu) ifFalse:[
+ menu := Menu new fromLiteralArrayEncoding:menu
+ ].
+
+ resourceKeys := Set new.
+ menu allItemsDo:[:aMenuItem |
+ aMenuItem translateLabel ifTrue:[
+ aMenuItem isSeparatorItem ifFalse:[
+ resourceKeys add:aMenuItem label.
+ ]
+ ]
+ ].
+ ^ resourceKeys
+!
+
+extractTranslationsFromMethod:aMethod
+ |mResources|
+
+ mResources := aMethod resources.
+ mResources notNil ifTrue:[
+ (mResources includesKey:#menu) ifTrue:[
+ ^ self extractTranslationsFromMenuSpecMethod:aMethod.
+ ].
+ (mResources includesKey:#canvas) ifTrue:[
+ ^ self extractTranslationsFromUISpecMethod:aMethod.
+ ].
+ (mResources includesKey:#help) ifTrue:[
+ ^ self extractTranslationsFromHelpSpecMethod:aMethod.
+ ].
+ (mResources includesKey:#tableColumns) ifTrue:[
+ ^ self extractTranslationsFromTableColumnsSpecMethod:aMethod.
+ ].
+
+ ^ self extractTranslationsFromSpecMethod:aMethod.
+ ].
+ ^ self extractTranslationsFromMethodsCode:aMethod
+!
+
+extractTranslationsFromMethodsCode:aMethod
+"/method:mthd selector:sel inClass:cls matchesParseTreeMatcher:aMatcher
+ |codeStrings matcher parseTree resourceKeys|
+
+ parseTree := RBParser
+ parseMethod:aMethod source
+ onError: [:str :pos | Transcript showCR:str. Transcript showCR:pos.
+ nil].
+ parseTree isNil ifTrue:[^ #() ].
+
+ codeStrings :=
+ #(
+ 'resources `@msg: `@args'
+ 'self resources `@msg: `@args'
+ 'self class resources `@msg: `@args'
+ 'self classResources `@msg: `@args'
+ ).
+
+ resourceKeys := Set new.
+
+ matcher := ParseTreeSearcher new.
+ matcher
+ matchesAnyOf: codeStrings
+ do: [:aNode :answer |
+ |sel keyStringArgNode keyStringArg|
+
+ sel := aNode selector.
+ ((sel startsWith:'string:') or:[(sel startsWith:'at:')]) ifTrue:[
+ keyStringArgNode := aNode arguments at:1.
+ keyStringArgNode isLiteral ifTrue:[
+ keyStringArg := keyStringArgNode value.
+ keyStringArg isString ifTrue:[
+ resourceKeys add:keyStringArg.
+ ] ifFalse:[
+ Transcript
+ showCR:(resources
+ string:'Cannot derive resourceKey from non-string: %1 in %2'
+ with:keyStringArgNode formattedCode
+ with:aMethod selector).
+ ].
+ ] ifFalse:[
+ Transcript
+ showCR:(resources
+ string:'Cannot derive resourceKey from non-literal: %1 in %2'
+ with:keyStringArgNode formattedCode
+ with:aMethod selector).
+ ].
+ ].
+ aNode
+ ].
+
+ matcher executeTree: parseTree initialAnswer: nil.
+ ^ resourceKeys
+!
+
+extractTranslationsFromSpecMethod:aMethod
+ ^ #()
+!
+
+extractTranslationsFromTableColumnsSpecMethod:aMethod
+ |columnDescription resourceKeys|
+
+ columnDescription := aMethod mclass theNonMetaclass perform:aMethod selector.
+ columnDescription isNil ifTrue:[ ^ #() ].
+
+ (columnDescription first isKindOf:DataSetColumnSpec) ifFalse:[
+ columnDescription := columnDescription collect:[:el | DataSetColumnSpec new fromLiteralArrayEncoding:el].
+ ].
+
+ resourceKeys := Set new.
+ columnDescription do:[:aColumnSpec |
+ aColumnSpec translateLabel ifTrue:[
+ resourceKeys add:aColumnSpec label.
+ ]
+ ].
+ ^ resourceKeys
+!
+
+extractTranslationsFromUISpecMethod:aMethod
+ |spec resourceKeys visitor|
+
+ spec := aMethod mclass theNonMetaclass perform:aMethod selector.
+ spec isNil ifTrue:[ ^ #() ].
+
+ (spec isKindOf:UISpecification) ifFalse:[
+ spec := UISpecification from:spec
+ ].
+
+ resourceKeys := Set new.
+
+ visitor := UISpecVisitor new.
+ spec acceptVisitor:visitor.
+
+ ^ visitor translatedLabels
+! !
+
+!InternationalLanguageTranslationEditor methodsFor:'queries'!
+
+hasUnsavedChanges
+ ^ modified
+! !
+
+!InternationalLanguageTranslationEditor methodsFor:'specs-dynamic'!
+
+columnInRow:row at:colIndex
+ |lang|
+
+ lang := self languageAtCol:colIndex.
+ ^ row atLanguage:lang
+!
+
+getBackgroundForRow:row rowNr:rowNr col:colIndex
+ |lang|
+
+ colIndex == 1 ifTrue:[^ nil].
+ lang := self languageAtCol:colIndex.
+ ^ (row atLanguage:lang) isNil ifTrue:[Color red lightened] ifFalse:nil
+!
+
+keyStringAndLanguageSelectionTableColumnDescription
+ |spec|
+
+ spec := OrderedCollection new.
+
+ spec add:
+ #(DataSetColumnSpec
+ label: 'Key'
+ labelAlignment: center
+ labelButtonType: Button
+ minWidth: 50
+ model: keyStringInRow:
+ isResizeable: true
+ canSelect: true
+ showRowSeparator: true
+ showColSeparator: true
+ ).
+
+ self shownLanguages do:[:lang |
+ |entry|
+
+ entry :=
+ #(DataSetColumnSpec
+ label: lang
+ labelAlignment: center
+ labelButtonType: Button
+ minWidth: 50
+ model: #columnInRow:at:
+ canSelect: true
+ isResizeable: true
+ showRowSeparator: true
+ showColSeparator: true
+ backgroundSelector: #getBackgroundForRow:rowNr:col:
+ ).
+ entry := entry copy.
+ entry replaceAll:#lang with:lang.
+ spec add: entry
+ ].
+ ^ spec
+!
+
+keyStringInRow:row
+ ^ row keyString
+! !
+
+!InternationalLanguageTranslationEditor methodsFor:'user actions'!
+
+selectionChanged
+ |rowSelectionIndex colSelectionIndex language selectedKey originalText languageText
+ answer|
+
+ colSelectionIndex := dataSetView selectedColIndex.
+ language := colSelectionIndex > 1 ifTrue:[ shownLanguages at:colSelectionIndex-1 ] ifFalse:nil.
+
+ rowSelectionIndex := self selectedKeyRow value.
+ rowSelectionIndex ~~ 0 ifTrue:[
+ selectedKey := keyStringsToLanguageMappings keyAt:rowSelectionIndex.
+ originalText := selectedKey storeString.
+ language notNil ifTrue:[
+ languageText := keyStringsToLanguageMappings at:selectedKey language:language.
+ languageText notNil ifTrue:[
+ languageText := languageText storeString.
+ ]
+ ]
+ ].
+
+ self originalTextModifiedHolder value ifTrue:[
+ answer := OptionBox
+ request:'Accept changed original text (key) ?'
+ label:'Original text (key) changed'
+ image:(WarningBox iconBitmap)
+ buttonLabels:#('Cancel' 'Accept' 'Accept As New')
+ values:#(nil #accept #acceptAsNew)
+ default:#acceptAsNew.
+
+ answer isNil ifTrue:[^ self ].
+ answer == #accept ifTrue:[
+self halt. ].
+ answer == #acceptAsNew ifTrue:[
+self halt. ].
+ ].
+ self languageTextModifiedHolder value ifTrue:[ self halt.
+ (Dialog confirm:'Accept changed translation ?') ifTrue:[
+ self halt.
+ ]
+ ].
+
+ self originalTextHolder value:originalText.
+ self languageTextHolder value:languageText.
+
+ self originalTextModifiedHolder value:false.
+ self languageTextModifiedHolder value:false.
+!
+
+shownLanguagesChanged
+ self keyStringAndLanguageSelectionTableColumnDescriptionHolder
+ value:(self keyStringAndLanguageSelectionTableColumnDescription).
+!
+
+stopApplication
+ |p|
+
+ (p := monitoredApplication) notNil ifTrue:[
+ p terminate.
+ ].
+! !
+
+!InternationalLanguageTranslationEditor::AccessCollectingPseudoResourcePack methodsFor:'accessing'!
+
+realResourcePack:something
+ realResourcePack := something.
+! !
+
+!InternationalLanguageTranslationEditor::KeyStringsToLanguageMappings class methodsFor:'instance creation'!
+
+new
+ ^ self basicNew initialize
+! !
+
+!InternationalLanguageTranslationEditor::KeyStringsToLanguageMappings methodsFor:'accessing'!
+
+addKey:aKey
+ keys add:aKey.
+ self changed.
+!
+
+addKeys:aCollectionOfKey
+ keys addAll:aCollectionOfKey.
+ self changed.
+!
+
+addLanguage:lang
+ languages add:lang.
+ languageMappings at:lang put:(Dictionary new).
+!
+
+at:aKey language:language
+ ^ (languageMappings at:language) at:aKey ifAbsent:nil
+!
+
+at:aKey language:language put:value
+ self addKey:aKey.
+ ^ (languageMappings at:language) at:aKey put:value
+!
+
+keyAt:index
+ ^ keys at:index.
+!
+
+keyAt:index ifAbsent:exceptionalValue
+ ^ keys at:index ifAbsent:exceptionalValue.
+!
+
+keys
+ ^ keys
+!
+
+languages
+ ^ languages
+!
+
+removeKey:aKey
+ keys remove:aKey ifAbsent:[].
+ languageMappings do:[:eachMapping |
+ eachMapping removeKey:aKey ifAbsent:[].
+ ].
+ self changed.
+!
+
+size
+ ^ keys size
+! !
+
+!InternationalLanguageTranslationEditor::KeyStringsToLanguageMappings methodsFor:'enumerating'!
+
+do:aBlock
+ keys do:[:eachKey |
+ aBlock value:(InternationalLanguageTranslationEditor::LanguageMappingRow new
+ key:eachKey; mappings:self).
+ ].
+! !
+
+!InternationalLanguageTranslationEditor::KeyStringsToLanguageMappings methodsFor:'initialization'!
+
+initialize
+ super initialize.
+
+ keys := OrderedSet new.
+ languages := OrderedCollection new.
+ languageMappings := Dictionary new.
+
+ keys add:'open'.
+ keys add:'close'.
+ keys add:'yes'.
+ keys add:'no'.
+
+ self addLanguage:#'de'.
+ self addLanguage:#'fr'.
+
+ self at:'open' language:#'de' put:'öffnen'.
+ self at:'close' language:#'de' put:'schliessen'.
+ self at:'yes' language:#'de' put:'ja'.
+ self at:'no' language:#'de' put:'nein'.
+ self at:'cancel' language:#'de' put:'abbrechen'.
+
+ self at:'open' language:#'fr' put:'ouvrir'.
+ self at:'close' language:#'fr' put:'fermer'.
+ self at:'yes' language:#'fr' put:'oui'.
+ self at:'no' language:#'fr' put:'non'.
+! !
+
+!InternationalLanguageTranslationEditor::KeyStringsToLanguageMappings methodsFor:'private'!
+
+atLanguage:lang
+ ^ languageMappings at:lang
+!
+
+atLanguageIndex:idx
+ |lang|
+
+ lang := languages at:idx.
+ ^ self atLanguage:lang.
+! !
+
+!InternationalLanguageTranslationEditor::KeyStringsToLanguageMappings methodsFor:'queries'!
+
+includesKey:aKey
+ ^ keys includes:aKey
+!
+
+includesLanguage:lang
+ ^ languages includes:lang
+!
+
+indexOfKey:aKey
+ ^ keys indexOf:aKey
+! !
+
+!InternationalLanguageTranslationEditor::LanguageMappingRow methodsFor:'accessing'!
+
+atLanguage:language
+ ^ (mappings atLanguage:language) at: key ifAbsent:nil
+!
+
+columnAt:columnNr
+ ^ (mappings atLanguageIndex:columnNr-1) at: key ifAbsent:nil
+!
+
+key:something
+ key := something.
+!
+
+keyString
+ ^ key
+!
+
+mappings:something
+ mappings := something.
+! !
+
+!InternationalLanguageTranslationEditor::UISpecVisitor methodsFor:'accessing'!
+
+translatedLabels
+ ^ translatedLabels ? #()
+! !
+
+!InternationalLanguageTranslationEditor::UISpecVisitor methodsFor:'visiting'!
+
+visitObject:anObject with:aParameter
+ (anObject isKindOf:UISpecification) ifTrue:[
+ (anObject respondsTo:#translateLabel) ifTrue:[
+ anObject translateLabel == true ifTrue:[
+ translatedLabels isNil ifTrue:[
+ translatedLabels := Set new.
+ ].
+ translatedLabels add:anObject label.
+ ].
+ ].
+ ].
+ self visitChildrenOf:anObject.
+! !
+
+!InternationalLanguageTranslationEditor class methodsFor:'documentation'!
+
+version
+ ^ '$Header$'
+! !