Tools__InternationalLanguageTranslationEditor.st
author Claus Gittinger <cg@exept.de>
Tue, 11 Dec 2007 18:49:39 +0100
changeset 2219 dc5bf7573298
parent 2163 641467b2f522
child 2323 9b257cbd0ea9
permissions -rw-r--r--
changed #doBrowseActionMethod:

"{ 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 languageTextAcceptHolder
		inSingleFileMode lastExtractedProject lastLanguage
		lastSelectedKey autoAcceptHolder languageEditor
		selectedColIndexHolder exampleLanguageSelectionHolder
		exampleLanguageTextHolder pastePreviousTranslationEnableHolder
		searchForSimilarTranslationEnableHolder alwaysWriteUTF8Holder
		lastNameSpace'
	classVariableNames:'LastExtractedClass LastExtractedApplicationClass
		LastExtractedProject'
	poolDictionaries:''
	category:'Interface-UIPainter'
!

Object subclass:#AccessCollectingPseudoResourcePack
	instanceVariableNames:'collectedKeys realResourcePack'
	classVariableNames:''
	poolDictionaries:''
	privateIn:InternationalLanguageTranslationEditor
!

Collection subclass:#KeyStringsToLanguageMappings
	instanceVariableNames:'keys keyInfo perLanguageInfo perLanguageMappings languageMappings
		languages rowPerKey'
	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:Tools::InternationalLanguageTranslationEditor andSelector:#windowSpec
     Tools::InternationalLanguageTranslationEditor new openInterface:#windowSpec
     Tools::InternationalLanguageTranslationEditor open
    "

    <resource: #canvas>

    ^ 
     #(FullSpec
        name: windowSpec
        window: 
       (WindowSpec
          label: 'InternationalLanguageTranslationEditor'
          name: 'InternationalLanguageTranslationEditor'
          min: (Point 10 10)
          bounds: (Rectangle 0 0 778 614)
          menu: mainMenu
        )
        component: 
       (SpecCollection
          collection: (
           (MenuPanelSpec
              name: 'ToolBar'
              layout: (LayoutFrame 0 0 0 0 0 1 30 0)
              menu: menuToolBar
              textDefault: true
            )
           (VariableVerticalPanelSpec
              name: 'VariableVerticalPanel2'
              layout: (LayoutFrame 0 0 30 0 0 1 0 1)
              component: 
             (SpecCollection
                collection: (
                 (DataSetSpec
                    name: 'KeyStringAndLanguageSelectionTable'
                    model: selectedKeyRow
                    menu: keyStringAndLanguageSelectionTableMenu
                    hasHorizontalScrollBar: true
                    hasVerticalScrollBar: true
                    dataList: keyStringAndLanguageSelectionTable
                    columnHolder: keyStringAndLanguageSelectionTableColumnDescriptionHolder
                    beDependentOfRows: true
                    columnAdaptor: yourself
                    postBuildCallback: postBuildDataSet:
                  )
                 (VariableVerticalPanelSpec
                    name: 'VariableVerticalPanel1'
                    component: 
                   (SpecCollection
                      collection: (
                       (ViewSpec
                          name: 'Box1'
                          component: 
                         (SpecCollection
                            collection: (
                             (LabelSpec
                                label: 'Original String (Key):'
                                name: 'Label2'
                                layout: (LayoutFrame 0 0 -2 0 0 1 28 0)
                                translateLabel: true
                                adjust: left
                              )
                             (TextEditorSpec
                                name: 'OriginalText'
                                layout: (LayoutFrame 0 0 27 0 0 1 -2 1)
                                model: originalTextHolder
                                hasHorizontalScrollBar: true
                                hasVerticalScrollBar: true
                                modifiedChannel: originalTextModifiedHolder
                                acceptCallBack: languageTextAccepted
                              )
                             )
                           
                          )
                        )
                       (ViewSpec
                          name: 'Box3'
                          component: 
                         (SpecCollection
                            collection: (
                             (LabelSpec
                                label: 'Select Another Language as example:'
                                name: 'Label3'
                                layout: (LayoutFrame 0 0 -6 0 0 1 24 0)
                                translateLabel: true
                                adjust: left
                              )
                             (ComboBoxSpec
                                name: 'ComboBox1'
                                layout: (LayoutFrame 197 0 -2 0 322 0 18 0)
                                model: exampleLanguageSelectionHolder
                                immediateAccept: false
                                acceptOnLeave: true
                                acceptOnLostFocus: true
                                acceptOnPointerLeave: false
                                comboList: shownLanguages
                                useIndex: false
                              )
                             (TextEditorSpec
                                name: 'ExampleLanguageText'
                                layout: (LayoutFrame 0 0 30 0 0 1 0 1)
                                model: exampleLanguageTextHolder
                                hasHorizontalScrollBar: true
                                hasVerticalScrollBar: true
                                isReadOnly: true
                              )
                             )
                           
                          )
                        )
                       (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
                                acceptChannel: languageTextAcceptHolder
                                modifiedChannel: languageTextModifiedHolder
                                acceptCallBack: languageTextAccepted
                                postBuildCallback: languageEditorBuilt:
                              )
                             (ActionButtonSpec
                                label: 'Paste Previous'
                                name: 'pastePreviousTranslation'
                                layout: (LayoutOrigin 0 0.83085250338295 0 0.03448275862069)
                                translateLabel: true
                                model: pastePreviousTranslationInLanguageText
                                enableChannel: pastePreviousTranslationEnableHolder
                                disabledLogo: 'Paste Previous'
                              )
                             )
                           
                          )
                        )
                       )
                     
                    )
                    handles: (Any 0.33333333333333 0.66666666666667 1.0)
                  )
                 )
               
              )
              handles: (Any 0.5 1.0)
            )
           )
         
        )
      )
! !

!InternationalLanguageTranslationEditor class methodsFor:'menu specs'!

keyStringAndLanguageSelectionTableMenu
    "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:Tools::InternationalLanguageTranslationEditor andSelector:#keyStringAndLanguageSelectionTableMenu
     (Menu new fromLiteralArrayEncoding:(Tools::InternationalLanguageTranslationEditor keyStringAndLanguageSelectionTableMenu)) startUp
    "

    <resource: #menu>

    ^ 
     #(Menu
        (
         (MenuItem
            label: 'Current NameSpace:'
            itemValue: changeLastNameSpace
            translateLabel: true
          )
         (MenuItem
            label: 'Search String in Current NameSpace:'
            itemValue: searchStringInLastNameSpace
            translateLabel: true
          )
         )
        nil
        nil
      )
!

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:Tools::InternationalLanguageTranslationEditor andSelector:#mainMenu
     (Menu new fromLiteralArrayEncoding:(Tools::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 All Resource Files'
                  itemValue: menuSaveAll
                  translateLabel: true
                )
               (MenuItem
                  label: 'Save Resource File'
                  itemValue: menuSave
                  translateLabel: true
                )
               (MenuItem
                  label: 'Save Resource File As...'
                  itemValue: menuSaveAs
                  translateLabel: true
                )
               (MenuItem
                  label: '-'
                )
               (MenuItem
                  label: 'Current NameSpace:'
                  itemValue: changeLastNameSpace
                  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: 'Extract from Project...'
                  itemValue: extractTranslationsFromProject
                  translateLabel: true
                )
               (MenuItem
                  label: 'Extract from NameSpace...'
                  itemValue: extractTranslationsFromNameSpace
                  translateLabel: true
                )
               (MenuItem
                  label: '-'
                )
               (MenuItem
                  label: 'Run Application and Collect Translations...'
                  itemValue: runApplicationAndCollectTranslations
                  translateLabel: true
                )
               )
              nil
              nil
            )
          )
         (MenuItem
            label: 'Preferences'
            translateLabel: true
            submenu: 
           (Menu
              (
               (MenuItem
                  label: 'Auto Accept Changes'
                  translateLabel: true
                  indication: autoAcceptHolder
                )
               (MenuItem
                  label: 'Search For Similar Translations'
                  translateLabel: true
                  indication: searchForSimilarTranslationEnableHolder
                )
               (MenuItem
                  label: 'Always Write UTF8'
                  translateLabel: true
                  indication: alwaysWriteUTF8Holder
                )
               )
              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
      )
!

menuItemsEditLanguage
    "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:Tools::InternationalLanguageTranslationEditor andSelector:#menu
     (Menu new fromLiteralArrayEncoding:(Tools::InternationalLanguageTranslationEditor menu)) startUp
    "

    <resource: #menu>

    ^ 
     #(Menu
        (
         (MenuItem
            enabled: pastePreviousTranslationEnableHolder
            label: 'Paste Previous Translation'
            itemValue: pastePreviousTranslationInLanguageText
            nameKey: pastePreviousTranslationInLanguageText
            translateLabel: true
          )
         )
        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:Tools::InternationalLanguageTranslationEditor andSelector:#menuToolBar
     (Menu new fromLiteralArrayEncoding:(Tools::InternationalLanguageTranslationEditor menuToolBar)) startUp
    "

    <resource: #menu>

    ^ 
     #(Menu
        (
         (MenuItem
            label: 'Save'
            itemValue: menuSave
            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 class methodsFor:'tableColumns specs'!

keyTableColumn
    "This resource specification was automatically generated
     by the DataSetBuilder of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the DataSetBuilder may not be able to read the specification."

    "
     DataSetBuilder new openOnClass:Tools::InternationalLanguageTranslationEditor andSelector:#keyTableColumn
    "

    <resource: #tableColumns>

    ^#(
      (DataSetColumnSpec
         label: 'Key'
         labelButtonType: Button
         minWidth: 50
         model: keyStringInRow:
       )
      )
!

languageTableColumn
    "This resource specification was automatically generated
     by the DataSetBuilder of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the DataSetBuilder may not be able to read the specification."

    "
     DataSetBuilder new openOnClass:Tools::InternationalLanguageTranslationEditor andSelector:#languageTableColumn
    "

    <resource: #tableColumns>

    ^#(
      (DataSetColumnSpec
         label: lang
         labelButtonType: Button
         minWidth: 50
         editorType: None
         model: columnInRow:at:
         backgroundSelector: getBackgroundForRow:rowNr:col:
       )
      )
! !

!InternationalLanguageTranslationEditor methodsFor:'accessing'!

newLanguageText
"/   languageEditor accept
    ^self languageTextHolder value isNil 
        ifTrue:['']
        ifFalse:[self languageTextHolder value asCollectionOfLines first.]
!

selectedKey  
   "Returns the current selected key if there is one row seleted. Otherwise, returns nil"
     |rowSelectionIndex |

    keyStringsToLanguageMappings isNil ifTrue:[^nil].
    self selectedKeyRow value isNil ifTrue:[^nil].
    rowSelectionIndex := self selectedKeyRow value.
    rowSelectionIndex == 0 ifTrue:[^nil].
    ^ keyStringsToLanguageMappings keyAt:rowSelectionIndex.
! !

!InternationalLanguageTranslationEditor methodsFor:'additionalFuncionalities'!

searchForSimilarTranslation
    "Looks for a quite similar translation for the key and display a dialog with available options"
    |similarTranslationsAssociations selectedTranslation|

    self shouldSearchForSimilarTranslation ifFalse:[^self]. 

    similarTranslationsAssociations := keyStringsToLanguageMappings searchForSimilarTranslation: self selectedKey in: self currentLanguage.
    similarTranslationsAssociations isEmpty ifTrue:[^self].    

    similarTranslationsAssociations := similarTranslationsAssociations associations inject: OrderedCollection new into:[:collection :association |
        collection detect:[:selectedAssociation |
            selectedAssociation value sameAs: association value] ifNone:[collection add: association].
        collection].
    selectedTranslation := Dialog 
        choose:'Choose one if you consider it´s usefull to translate: 
    ', 
        '<', self selectedKey, '>  ', (self currentExampleLanguageText ifNil:[''])
        fromList: (similarTranslationsAssociations collect:[:each |  '<', each key, '>  ', each value])
        values: (similarTranslationsAssociations collect:[:each | each value])
        lines:10
        cancel: nil.      

    selectedTranslation notNil ifTrue:[self languageTextHolderValue: selectedTranslation]. 
! !

!InternationalLanguageTranslationEditor methodsFor:'aspects'!

alwaysWriteUTF8Holder
    alwaysWriteUTF8Holder isNil ifTrue:[alwaysWriteUTF8Holder := true asValue]. 
    ^ alwaysWriteUTF8Holder
!

autoAcceptHolder
    autoAcceptHolder isNil ifTrue:[autoAcceptHolder := true asValue]. 
    ^ autoAcceptHolder
!

exampleLanguageSelectionHolder
    exampleLanguageSelectionHolder isNil ifTrue:[
        exampleLanguageSelectionHolder := self exampleLanguageByDefault asValue.         
        exampleLanguageSelectionHolder addDependent:self.
    ]. 
    ^ exampleLanguageSelectionHolder
!

exampleLanguageTextHolder
    exampleLanguageTextHolder isNil ifTrue:[
        exampleLanguageTextHolder := '' asValue.
    ].
    ^ exampleLanguageTextHolder.
!

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.
!

languageTextAcceptHolder
    languageTextAcceptHolder isNil ifTrue:[
        languageTextAcceptHolder := false asValue.                        
    ].
    ^ languageTextAcceptHolder.
!

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.
!

pastePreviousTranslationEnableHolder
   pastePreviousTranslationEnableHolder isNil ifTrue:[pastePreviousTranslationEnableHolder := false asValue]. 
    ^ pastePreviousTranslationEnableHolder
!

searchForSimilarTranslationEnableHolder
   searchForSimilarTranslationEnableHolder isNil 
        ifTrue:[searchForSimilarTranslationEnableHolder := true asValue]. 
    ^ searchForSimilarTranslationEnableHolder
!

selectedKeyRow
    selectedKeyRow isNil ifTrue:[
        selectedKeyRow := ValueHolder new.
        selectedKeyRow onChangeSend:#selectionChanged to:self.
    ].
    ^ selectedKeyRow.
!

showMissingTranslationsOnly
    showMissingTranslationsOnly isNil ifTrue:[
        showMissingTranslationsOnly := false asValue.
        showMissingTranslationsOnly onChangeSend:#showMissingTranslationsOnlyChanged to:self.
    ].
    ^ 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:'change & update'!

languageTextHolderValue: aString

    self languageTextHolder value: aString.
    self languageTextModifiedHolder value:true.
!

update:something with:aParameter from:changedObject
    changedObject == shownLanguages ifTrue:[
         self shownLanguagesChanged.
         ^ self.
    ].
    changedObject == languageTextAcceptHolder ifTrue:[
         self updateLanguageTextModification.
         ^ self.
    ].
    changedObject == exampleLanguageSelectionHolder ifTrue:[
        self updateExampleLanguageText.
        ^ self.
    ].    
    changedObject == showMissingTranslationsOnly ifTrue:[
        self showMissingTranslationsOnlyChanged.
        ^ self.
    ]. 
!

updateCopyPreviousTranslationButtonEnabled

     self pastePreviousTranslationEnableHolder value: self shouldCopyPreviousTranslationButtonBeEnabled
!

updateExampleLanguageText

    self selectedKeyRow value isNil ifTrue:[^ self].
    self exampleLanguageTextHolder value:self currentExampleLanguageText
!

updateKeyStringsToLanguageMappings           

      keyStringsToLanguageMappings 
        at:lastSelectedKey 
        language:lastLanguage 
        put: self newLanguageText.
!

updateLanguageAndKeySelection

    self originalTextHolder value: self selectedKey.
    self languageTextHolder value: (self languageTextFromSelectedKeyFor: self currentLanguage).
    lastLanguage := self currentLanguage.
    lastSelectedKey := self selectedKey. 
!

updateLanguageTextModification 
     self languageTextModifiedHolder value ifTrue:[ 
        (self autoAccept or:[Dialog confirm:'Accept changed translation ?']) ifTrue:[
            self languageTextModifiedHolder value:false.
            self languageTextHolder value:languageEditor contents.
            lastLanguage notNil ifTrue:[self updateKeyStringsToLanguageMappings.]
        ]
    ].
!

updateOriginalTextModification

    |answer|

        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 originalTextModifiedHolder value:false. ].
            answer == #accept ifTrue:[
    self halt.        ].
            answer == #acceptAsNew ifTrue:[
    self halt.        ].
        ].
! !

!InternationalLanguageTranslationEditor methodsFor:'dialogs'!

requestEncoderDialog

   |box val characterCollection|

    val := '' asValue.
    box := Dialog new.
    (box addTextLabel:'Select or write the encoder') adjust:#left.
    box addVerticalSpace.
    characterCollection := CharacterEncoder supportedExternalEncodings 
        inject: OrderedCollection new
        into:[:collection :each |
            collection add: each first;
                        yourself].
    (box addComboBoxOn:val) list: characterCollection.
    box addOkButton.
    box open.
    ^val value
!

requestEncoderStringFor: lang
  "Returns an encoder string and updates the language's info"
    |encoderString encoder|
    encoderString := self requestEncoderDialog.
    encoderString notEmpty ifTrue:[
        encoder := CharacterEncoder encoderFor: encoderString ifAbsent:nil.
        encoder notNil ifTrue:[keyStringsToLanguageMappings atLanguage: lang putEncoder: encoder.].
    ].
    ^encoderString
!

requestFilename  

    |aFilename|

    aFilename := Dialog 
        requestFileName:'Name of resource file:'
        default:nil 
        pattern:'*.rs'.

    aFilename isEmptyOrNil ifTrue:[^ nil ].
    ^aFilename asFilename
!

requestFilenameFor: lang  
  "Returns a filename to save the language resource and updates the language's info"
    |aFilename|

    aFilename := Dialog 
        requestFileName:'Name of resource file to save ', lang asString, ' :'
        default:nil 
        pattern:'*.rs'.

    aFilename isEmptyOrNil ifTrue:[^ nil ].
    keyStringsToLanguageMappings atLanguage: lang putFilename: aFilename.
    ^aFilename asFilename
!

requestLanguage
    ^ Dialog 
        choose:'Which language do you want to save?'
        fromList:languagesList
        lines:10
! !

!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.
    inSingleFileMode := false.
    super initialize
!

languageEditorBuilt:aView
    languageEditor := aView.
!

postBuildDataSet:aView
    dataSetView := aView.
    aView selectedColIndexHolder onChangeSend:#selectionChanged to:self.
! !

!InternationalLanguageTranslationEditor methodsFor:'menu actions'!

addLanguage
    |lang|

    lang := Dialog request:'New language (ISO symbol):'.
    lang isEmptyOrNil ifTrue:[^ self].
    lang := lang asSymbol.
    (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:'.
    key isEmpty ifTrue:[^self].
    (self includesKey:key) ifFalse:[
        keyStringsToLanguageMappings addKey:key.
        modified := true.
    ].
   index := keyStringsToLanguageMappings indexOfKey:key.
   self selectedKeyRow value:index
!

changeLastNameSpace

    |nameSpace defaultNameSpace|

    lastNameSpace notNil ifTrue:[defaultNameSpace := lastNameSpace name].
    nameSpace := Dialog requestNameSpace:'NameSpace:' title:'Search String in Name Space:' initialAnswer:defaultNameSpace.
    nameSpace isNil ifTrue:[^self].
    nameSpace := Smalltalk at:nameSpace asSymbol.
    nameSpace isNil ifTrue:[
        ^Dialog information:(resources string:'No such nameSpace exists.?') 
    ].
    lastNameSpace := nameSpace.
!

extractTranslationsFromClass
    |aClass newTranslations|

    aClass := Dialog 
                requestClass:'Class to extract translations from:'
                okLabel:'OK' 
                initialAnswer:(lastExtractedClass ? LastExtractedClass).
    aClass isNil ifTrue:[^ self ].

    lastExtractedClass := LastExtractedClass := aClass.

    newTranslations := self extractTranslationsFromClass:aClass.
    self addAllTranslations:newTranslations.
!

extractTranslationsFromNameSpace

    |newTranslations|

    self changeLastNameSpace.
    lastNameSpace isNil ifTrue:[^self.].
    newTranslations := OrderedCollection new.
    lastNameSpace allClassesDo:[:eachClass |
        newTranslations addAll:( self extractTranslationsFromClass:eachClass theNonMetaclass).
    ].
    self addAllTranslations:newTranslations.
!

extractTranslationsFromProject
    |box projectID newTranslations|

    box := ListSelectionBox new.
"/    box useComboBoxWithList:(Smalltalk allProjectIDs).
    box title:(resources string:'Project to extract translations from:').
    box list:Smalltalk allProjectIDs.
    box okAction:[:sel | projectID := sel].
    box initialText:(lastExtractedProject ? LastExtractedProject).
    box label:'Find Translations in Project'.

    box showAtPointer.

    projectID notNil ifTrue:[
        projectID := projectID withoutSeparators asSymbol.
    ].
    projectID isEmptyOrNil ifTrue:[^ self ].

    lastExtractedProject := LastExtractedProject := projectID.

    newTranslations := Set new.

    Smalltalk allClassesDo:[:eachClass |
        eachClass theNonMetaclass package == projectID ifTrue:[
"/ eachClass isLoaded ifTrue:[ self halt. ].
            newTranslations addAll:( self extractTranslationsFromClass:eachClass theNonMetaclass).
        ]
    ].

    self addAllTranslations:newTranslations.
!

inspectCanvasMissingStrings

    |spec nameSpace missingStrings|

    missingStrings := OrderedCollection new.
    nameSpace := Dialog requestNameSpace:'NameSpace:' title:'Specify NameSpace to look for missing strings' initialAnswer:nil.
    nameSpace := Smalltalk at:nameSpace asSymbol.
    nameSpace isNil ifTrue:[
        ^Dialog information:(resources string:'No such nameSpace exists.?') 
    ].

    nameSpace allClassesDo:[:cls |
        cls theMetaclass methodsDo:[:m |
            m hasResource ifTrue:[
                (m resources includesKey:#canvas) ifTrue:[
                    spec := (cls perform:m selector) decodeAsLiteralArray.
                    spec do:[:eachComponent |
                        eachComponent translationKeysDo:[:k | 
                            (self includesKey: k) ifFalse:[
                                missingStrings add: k. 
                                Transcript showCR: k storeString, '                         ', m printString]]
                    ]
                ]
            ]
        ]
    ].
    missingStrings asSet inspect
!

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
    |aFilename|

    self withWaitCursorDo:[
        aFilename := self requestFilename.
        aFilename isNil ifTrue:[^ self ].
        self readResourceFile:aFilename.
    ]
!

menuSave
"Saves the language selected in the fileName from where the language resource was obtained."
    |lang|

    lang := self requestLanguage.
    lang isNil ifTrue:[^ self].
    self saveLanguage: lang
!

menuSaveAll
"Saves all the languages in the fileName from where the language resource was obtained."
    keyStringsToLanguageMappings languagesInUse do:[:each | self saveLanguage: each]. 
!

menuSaveAs
"Saves the language selected in the specified fileName."
     |lang aFilename|

    lang := self requestLanguage.
    lang isNil ifTrue:[^ self]. 
    aFilename := self requestFilenameFor:lang.
    aFilename isNil ifTrue:[^ self].
    self saveResourceFile:aFilename for:lang asSymbol
!

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
    |lang|

    lang := Dialog choose:'For which language ?' fromList:languagesList lines:10.
    lang isNil ifTrue:[^ self ].

    self readResourceFile:aFilename asLanguage:lang asSymbol
!

removeLanguage
    |lang|

    lang := Dialog choose:'Which language do you want to remove?' fromList:languagesList lines:10.
    lang isNil ifTrue:[^ self ].
    (Dialog confirm: 'Are you sure to remove the language ', lang ) ifTrue:[
          self languagesList remove:lang.
          self shownLanguages remove:lang.
    ].      
!

removeTranslation
    |rowSelectionIndex selectedKey|

    rowSelectionIndex := self selectedKeyRow value.
    rowSelectionIndex isNil ifTrue:[^self].
    rowSelectionIndex ~~ 0 ifTrue:[
        selectedKey := keyStringsToLanguageMappings keyAt:rowSelectionIndex ifAbsent:nil.
        selectedKey isNil ifTrue:[^self].
        (Dialog confirm:(resources string:'Really remove key %1' with:selectedKey)) ifTrue:[
            keyStringsToLanguageMappings removeKey:selectedKey.
        ].
    ].
!

runApplicationAndCollectTranslations
    |applicationClass newTranslations pseudoPack app startSelector|

    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 ].
    applicationClass isNamespace ifTrue:[
        Dialog warn:'Entered class is a NameSpace'.
        ^ self.
    ].

    applicationClass isVisualStartable ifTrue:[
        startSelector := #open
    ] ifFalse:[
        startSelector := Dialog
                    request:'Entered class seems to be no application class. Ok to start using selector:'
                    initialAnswer:((applicationClass respondsTo:#'start')
                                        ifTrue:#'start'
                                        ifFalse:#'new')
                    okLabel:'START'
                    title:'Start Application'.
        startSelector isNil ifTrue:[
            ^ self
        ].
        startSelector := startSelector asSymbol.
    ].

    lastExtractedApplicationClass := LastExtractedApplicationClass := applicationClass.

    newTranslations := Set new.

    pseudoPack := AccessCollectingPseudoResourcePack new.
    pseudoPack realResourcePack:(applicationClass classResources).

    self stopApplicationIconVisibleHolder value:true.

    monitoredApplication := [
        [
            app := applicationClass new.
            app perform:startSelector.
            app window waitUntilVisible.
            app window waitUntilClosed.
        ] ensure:[
            app closeRequest.
            self stopApplicationIconVisibleHolder value:false.
            monitoredApplication := nil.
        ].
    ] fork.
!

searchStringInLastNameSpace

    |selectedKey browser|

    selectedKey := self selectedKey.
    selectedKey isNil ifTrue:[^Dialog information: 'No selected key'].
    browser := NewSystemBrowser new "open".
    browser allButOpen.
    browser lastSearchPatterns first = selectedKey ifFalse:[
        browser lastSearchPatterns addFirst: selectedKey
    ].
    lastNameSpace isNil ifTrue:[
        self changeLastNameSpace.
    ].
    lastNameSpace notNil ifTrue:[
"/        browser navigationState selectedClasses value: lastNameSpace allClasses.
        browser navigationState nameSpaceFilter value: (OrderedCollection with:lastNameSpace name).
        browser navigationState selectedNamespaces value: (OrderedCollection with:lastNameSpace name).
    ].
    self withWaitCursorDo:[
        browser browseMenuMethodsWithString
    ].
! !

!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.
        self shownLanguages add:newLang.
    ]
!

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'!

addAllTranslations:newTranslations
    |newTranslationKeys stringKeys nonStringKeys|

    newTranslationKeys := newTranslations select:[:k | k notEmpty and:[k isString not or:[k isBlank not]]].
    newTranslationKeys := newTranslationKeys select:[:k | (keyStringsToLanguageMappings includesKey:k) not].
    newTranslationKeys := newTranslationKeys 
                                collect:[:k | 
                                        (k endsWith:'...') ifTrue:[
                                            k copyWithoutLast:3.
                                        ] ifFalse:[
                                            ('.:?' includes:k last) ifTrue:[
                                                k copyWithoutLast:1.
                                            ] ifFalse:[
                                                k
                                        ]]].
    newTranslationKeys := newTranslationKeys asSet.

    newTranslationKeys notEmpty ifTrue:[
        stringKeys := newTranslationKeys select:[:k | k isString].
        nonStringKeys := newTranslationKeys select:[:k | k isString not].

        stringKeys := stringKeys asSortedCollection.
        keyStringsToLanguageMappings addKeys:stringKeys.
        keyStringsToLanguageMappings addKeys:nonStringKeys.
        modified := true.
    ].
!

extractTranslationsFromClass:aClass
    |newTranslations|

    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
!

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'!

autoAccept                                                   

    ^ self autoAcceptHolder value
!

currentExampleLanguageText           
   "Returns the language text corresponding for the current selected key and the example language selection"

  ^self languageTextFromSelectedKeyFor: self exampleLanguageSelectionHolder value
!

currentLanguage

    |colSelectionIndex |

    colSelectionIndex := dataSetView selectedColIndex.
    ^colSelectionIndex > 1 ifTrue:[ shownLanguages at:colSelectionIndex-1 ] ifFalse:nil.
!

exampleLanguageByDefault

    ^self shownLanguages isEmpty
        ifTrue:[nil]
        ifFalse:[self shownLanguages first]
!

hasFirstRowSelection
    self selectedKeyRow isNil ifTrue:[^false].
    ^ self selectedKeyRow value > 1
!

hasLanguageSelection
    dataSetView selectedColIndex isNil ifTrue:[^false].
    ^ dataSetView selectedColIndex > 1
!

hasUnsavedChanges
    ^ modified
!

includesKey: aKey
    keyStringsToLanguageMappings isNil ifTrue:[^false].
    ^keyStringsToLanguageMappings includesKey:aKey
!

isSearchForSimilarTranslationEnabled

    ^self searchForSimilarTranslationEnableHolder value
!

languageTextFromKey: aKeyIndex for: language
    "Returns the language text corresponding for the aKeyIndex and the received language"    

    language isNil ifTrue:[^''].
    ^keyStringsToLanguageMappings at: aKeyIndex language:language.   
!

languageTextFromSelectedKeyFor: language
    "Returns the language text corresponding for the current selected key and the received language"    

    ^self languageTextFromKey: self selectedKey for: language 
!

shouldCopyPreviousTranslationButtonBeEnabled
    ^ self hasLanguageSelection 
        and:[self hasFirstRowSelection]
!

shouldSearchForSimilarTranslation

    self isSearchForSimilarTranslationEnabled ifFalse:[^false].
    (self languageTextHolder value notNil and:[self languageTextHolder value notEmpty]) ifTrue:[^false].
    (self hasLanguageSelection and:[self selectedKeyRow notNil]) ifFalse:[^false].
    ^true
! !

!InternationalLanguageTranslationEditor methodsFor:'read/write resourceFile'!

encoderAt: lang

    self alwaysWriteUTF8Holder value ifTrue:[^CharacterEncoder encoderForUTF8].
    ^keyStringsToLanguageMappings encoderAt: lang.
!

printEditingWarningOn: aStream

    aStream nextPutAll: ';';
            cr;
            nextPutAll: '; WARNING:';
            cr;
            nextPutAll: '; this file contains national characters';
            cr;
            nextPutAll: '; DONT EDIT this file with an old vi !!';
            cr;
            nextPutAll: ';';
            cr; 
            cr.
!

printEncoderFor: lang on: aStream
    |characterEncoder encoderString|

    characterEncoder := self encoderAt: lang.
    encoderString := characterEncoder isNil 
        ifTrue:[self requestEncoderStringFor: lang]
        ifFalse:[characterEncoder nameOfEncoding printString].

    aStream nextPutAll: '#encoding';
            space;
            nextPutAll: encoderString;
            cr;
            cr.
!

printLanguage: lang on: aStream

    self printEncoderFor: lang on: aStream.
    self printEditingWarningOn: aStream.
    self printLanguageMappingsFor: lang on: aStream.
!

printLanguageMappingsFor: lang on: aStream

    |orderedAssociations maxKeySize characterEncoder|   

    characterEncoder := self encoderAt: lang.
    characterEncoder isNil ifTrue:[ characterEncoder := CharacterEncoder::NullEncoder ].
    orderedAssociations := keyStringsToLanguageMappings orderedLanguageMappingsAssociationsFor: lang. 

    maxKeySize := keyStringsToLanguageMappings maxKeySizeForLanguage: lang.     

    orderedAssociations do:[:association |
        aStream nextPutAll: (association key storeString paddedTo: maxKeySize) ; 
            nextPutAll: (String new: 10);
            nextPutAll: (characterEncoder encodeString: association value) storeString;
            cr.
        ].
!

readResourceFile:aFilename asLanguage:lang
    |resourcePack inStream lineString encoding decoder sortedKeys remainingKeys|

    aFilename exists ifFalse:[^ self ].

    resourcePack := ResourcePack new.

    inStream := aFilename readStream.
    [inStream atEnd] whileFalse:[
        lineString := inStream nextLine.
        (lineString notEmpty 
        and:[ (lineString startsWith:';') not ]) ifTrue:[
            ((lineString startsWith:'#') and:[(lineString startsWith:'#(') not]) ifTrue:[
                lineString := (lineString copyFrom:2) withoutSeparators.
                (lineString startsWith:'encoding ') ifTrue:[
                    encoding := ResourcePack extractEncodingFromLine:lineString.
                    decoder := CharacterEncoder encoderFor:encoding ifAbsent:nil.
                ].
            ] ifFalse:[
                ResourcePack
                    processResourceLine:lineString 
                    encoding:decoder 
                    file:aFilename pathName 
                    printErrorWith:[:msg | Transcript showCR:msg ] 
                    for:resourcePack
                    keepUselessTranslations:true.
            ].
        ].
    ].
    inStream close.                                                  

    sortedKeys := (resourcePack keys select:[:k | k isString]) asSortedCollection.
    remainingKeys := resourcePack keys select:[:k | k isString not].

    keyStringsToLanguageMappings atLanguage: lang putFilename: aFilename.
    keyStringsToLanguageMappings  atLanguage: lang putEncoder: decoder.

    sortedKeys do:[:k |
        keyStringsToLanguageMappings at:k language:lang put:(resourcePack at:k)
    ].
    remainingKeys do:[:k |
        keyStringsToLanguageMappings at:k language:lang put:(resourcePack at:k)
    ].
!

saveLanguage: lang
"Saves the language in the fileName from where the language resource was obtained."
    |aFilename|

    lang isNil ifTrue:[^ self].
    aFilename := keyStringsToLanguageMappings filenameAt:lang.
    aFilename isNil ifTrue:[
        aFilename := self requestFilenameFor: lang.
        aFilename isNil ifTrue:[^ self].
    ].
    self saveResourceFile:aFilename for:lang asSymbol
!

saveResourceFile: aFilename for: lang

    |aStream |

    keyStringsToLanguageMappings atLanguage: lang putFilename: aFilename.
    aStream := FileStream newFileNamed: aFilename.  
    self printLanguage: lang on: aStream.
    aStream flush;
            close.
    DialogBox information: 'The resource file for the language ', lang printString storeString, ' was saved in the file: ', aFilename nameString
! !

!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:(self class keyTableColumn first).

    self shownLanguages do:[:lang |
        |entry|

        entry := self class languageTableColumn first.
        entry := entry copy replaceAll:#lang with:lang.
        spec add: entry 
    ].
    ^ spec
!

keyStringInRow:row
    ^ row keyString
! !

!InternationalLanguageTranslationEditor methodsFor:'user actions'!

exampleLanguageSelectionChanged

   self updateExampleLanguageText.
!

languageTextAccepted                                   
    |nextRowIndex|
    keyStringsToLanguageMappings size = self selectedKeyRow value
        ifTrue:[ self updateLanguageTextModification.]
        ifFalse:[ 
            nextRowIndex := self selectedKeyRow value + 1.
            self selectedKeyRow value: nextRowIndex].
!

pastePreviousTranslationInLanguageText
    "Obtain the text from the previous translation and paste it into the languageTextEditor"
    
    | previousLanguageText previousLanguageRow|

    previousLanguageRow := dataSetView at:self selectedKeyRow value - 1
                ifAbsent:[^self].
    previousLanguageText := previousLanguageRow atLanguage: self currentLanguage.
    languageEditor selectAll.
    languageEditor pasteOrReplace:previousLanguageText.
    self languageTextModifiedHolder value:true.
!

selectionChanged                

   self updateOriginalTextModification.
   self updateLanguageTextModification.
   self updateLanguageAndKeySelection.
   self updateExampleLanguageText.

   self updateCopyPreviousTranslationButtonEnabled.

   self originalTextModifiedHolder value:false.
   self languageTextModifiedHolder value:false.

   self searchForSimilarTranslation.
!

showMissingTranslationsOnlyChanged
!

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 includes:aKey) ifFalse:[
        keys add:aKey.
        self changed.
    ]
!

addKeys:aCollectionOfKey
    keys addAll:aCollectionOfKey.
    self changed.
!

addLanguage:lang
    (languages includes:lang) ifFalse:[
        languages add:lang.
        perLanguageMappings at:lang put:(OrderedDictionary new).
    ]
!

at:aKey language:language
    ^ (perLanguageMappings at:language) at:aKey ifAbsent:nil
!

at:aKey language:language put:value
    self addKey:aKey.
    (perLanguageMappings at:language) at:aKey put:value.
    (self rowForKey:aKey) changed
!

atLanguage: lang putEncoder: aDecoder

^(self languageInfoAt: lang) at: self encoderKey put: aDecoder
!

atLanguage: lang putFilename: aFilename

^(self languageInfoAt: lang) at: self fileNameKey put: aFilename
!

decoderKey
   ^#decoder
!

encoderAt:lang 
    ^ (self languageInfoAt:lang) at: self encoderKey ifAbsent:[nil]
!

encoderKey
   ^#encoder
!

fileNameKey
    ^ #filename
!

filenameAt:lang 
    ^ (self languageInfoAt:lang) at: self fileNameKey ifAbsent:[nil]
!

keyAt:index
    ^ keys at:index ifAbsent:[nil].
!

keyAt:index ifAbsent:exceptionalValue
    ^ keys at:index ifAbsent:exceptionalValue.
!

keys
    ^ keys
!

languageInfoAt: lang 

^self perLanguageInfo at: lang ifAbsentPut:[Dictionary new]
!

languages
    ^ languages
!

languagesInUse
"Returns a collection of symbols for the languages that have mappings"

^self languages select:[:each | (self atLanguage: each) notEmpty]
!

orderedLanguageMappingsAssociationsFor: language
"Returns a collection of languageMappings associations (alphabetically ordered by keys) "
^(self atLanguage: language) associations asSortedCollection:[:a :b | a key < b key].
!

perLanguageInfo
    ^ perLanguageInfo
!

perLanguageInfo:something
    perLanguageInfo := something.
!

removeKey:aKey
    keys remove:aKey ifAbsent:[].
    perLanguageMappings do:[:eachMapping |
        eachMapping removeKey:aKey ifAbsent:[].
    ].
    self changed.
!

rowForKey:aKey
    ^ rowPerKey 
            at:aKey
            ifAbsentPut:[InternationalLanguageTranslationEditor::LanguageMappingRow new 
                            key:aKey; mappings:self].
!

size
    ^ keys size
! !

!InternationalLanguageTranslationEditor::KeyStringsToLanguageMappings methodsFor:'enumerating'!

do:aBlock
    keys do:[:eachKey |
        aBlock value:(self rowForKey:eachKey).
    ].
! !

!InternationalLanguageTranslationEditor::KeyStringsToLanguageMappings methodsFor:'initialization'!

initialize
    super initialize.

    keys := OrderedSet new.
    languages := OrderedCollection new.
    perLanguageMappings := Dictionary new.
    perLanguageInfo := Dictionary new.         
    rowPerKey := Dictionary new.

    self addLanguage:#'de'.
    self addLanguage:#'fr'.
    self addLanguage:#'es'.
    self addLanguage:(Smalltalk language).

    "/ self initializeDemoMappings.
!

initializeDemoMappings
    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
    ^ perLanguageMappings at:lang
!

atLanguageIndex:idx
    |lang|

    lang := languages at:idx.
    ^ self atLanguage:lang.
!

mappingAtLanguage:lang
    ^ perLanguageMappings at:lang
!

mappingAtLanguageIndex:idx
    |lang|

    lang := languages at:idx.
    ^ self mappingAtLanguage:lang.
! !

!InternationalLanguageTranslationEditor::KeyStringsToLanguageMappings methodsFor:'queries'!

includesKey:aKey
    ^ keys includes:aKey
!

includesLanguage:lang
    ^ languages includes:lang
!

indexOfKey:aKey
    ^ keys indexOf:aKey
!

maxKeySizeForLanguage: lang

^(self atLanguage: lang) keys inject: 0 into:[:maxSize :each |
    (maxSize < each size and:[each size < 100])
        ifTrue:[each size]
        ifFalse:[maxSize].].
!

searchForSimilarTranslation: aKey in: language
"Returns a collection of translation associations that corresponds to a quite similar key comparing with aKey"
|similarAssociations|
similarAssociations:= 
(self mappingAtLanguage: language) associationsSelect:[:each |
    ((each key sameAs: aKey) 
        or:[(aKey asUppercase startsWith: each key asUppercase)
            or:[((each key asUppercase levenshteinTo: aKey asUppercase)/ each key size) < 0.3
            ]])
     and:[each value notNil
            and:[each value notEmpty]]
].
^similarAssociations
! !

!InternationalLanguageTranslationEditor::LanguageMappingRow methodsFor:'accessing'!

atLanguage:language
    |translation|

    translation := (mappings mappingAtLanguage:language) at:key ifAbsent:nil.
    ^ translation isNil ifTrue:nil ifFalse:[translation printString]
!

columnAt:columnNr
    ^ (mappings mappingAtLanguageIndex:columnNr-1) at: key ifAbsent:nil
!

key:something
    key := something.
!

keyString
    ^ key printString
!

mappings:something
    mappings := something.
! !

!InternationalLanguageTranslationEditor::UISpecVisitor methodsFor:'accessing'!

translatedLabels
    ^ translatedLabels ? #()
! !

!InternationalLanguageTranslationEditor::UISpecVisitor methodsFor:'visiting'!

visitObject:anObject with:aParameter
    |l|

    (anObject isKindOf:UISpecification) ifTrue:[
        (anObject respondsTo:#translateLabel) ifTrue:[
            anObject translateLabel == true ifTrue:[
                translatedLabels isNil ifTrue:[
                    translatedLabels := Set new.
                ].
                l := anObject perform:#label ifNotUnderstood:nil.
                l notNil ifTrue:[
                    translatedLabels add:l.
                ].
            ].
        ].
    ].
    self visitChildrenOf:anObject.
! !

!InternationalLanguageTranslationEditor class methodsFor:'documentation'!

version
    ^ '$Header$'
! !