diff -r a7b9b0fd9b62 -r 8f226ff9b5e6 Tools__InternationalLanguageTranslationEditor.st --- /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 + " + + + + ^ + #(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 + " + + + + ^ + #(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 + " + + + + ^ + #(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//' ): + HTMLDocumentView openFullOnDocumentationFile:'TOP.html'. + + "/ add application-specific help files under the 'doc/online//help/appName' + "/ directory, and open a viewer with: + "/ HTMLDocumentView openFullOnDocumentationFile:'help//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 + + + ^ [ + |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$' +! !