Merge branch 'maint'
authorShawn O. Pearce <spearce@spearce.org>
Sun, 9 Sep 2007 09:03:56 +0000 (05:03 -0400)
committerShawn O. Pearce <spearce@spearce.org>
Sun, 9 Sep 2007 09:04:43 +0000 (05:04 -0400)
* maint:
git-gui: Avoid use of libdir in Makefile
git-gui: Disable Tk send in all git-gui sessions
git-gui: lib/index.tcl: handle files with % in the filename properly

1  2 
Makefile
git-gui.sh
lib/index.tcl
diff --combined Makefile
index df6f6b727569a0a3d5cf8e19fc3ddfacab0b8639,f11cf2676049529750c93e9584a3e89b7ac3e440..5b1ff914944a52dcc4519425562e34d6ceea3662
+++ b/Makefile
@@@ -47,8 -47,6 +47,8 @@@ ifndef 
        QUIET_GEN      = $(QUIET)echo '   ' GEN $@ &&
        QUIET_BUILT_IN = $(QUIET)echo '   ' BUILTIN $@ &&
        QUIET_INDEX    = $(QUIET)echo '   ' INDEX $(dir $@) &&
 +      QUIET_MSGFMT0  = $(QUIET)printf '    MSGFMT %12s ' $@ && v=`
 +      QUIET_MSGFMT1  = 2>&1` && echo "$$v" | sed -e 's/fuzzy translations/fuzzy/' | sed -e 's/ messages//g'
        QUIET_2DEVNULL = 2>/dev/null
  
        INSTALL_D0 = dir=
@@@ -78,8 -76,8 +78,8 @@@ SHELL_PATH_SQ = $(subst ','\'',$(SHELL_
  TCL_PATH_SQ = $(subst ','\'',$(TCL_PATH))
  TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH))
  
libdir   ?= $(sharedir)/git-gui/lib
- libdir_SQ = $(subst ','\'',$(libdir))
gg_libdir ?= $(sharedir)/git-gui/lib
+ libdir_SQ  = $(subst ','\'',$(gg_libdir))
  
  exedir    = $(dir $(gitexecdir))share/git-gui/lib
  exedir_SQ = $(subst ','\'',$(exedir))
@@@ -105,21 -103,6 +105,21 @@@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %
  $(GITGUI_BUILT_INS): git-gui
        $(QUIET_BUILT_IN)rm -f $@ && ln git-gui $@
  
- msgsdir    ?= $(libdir)/msgs
 +XGETTEXT   ?= xgettext
 +MSGFMT     ?= msgfmt
++msgsdir     = $(gg_libdir)/msgs
 +msgsdir_SQ  = $(subst ','\'',$(msgsdir))
 +PO_TEMPLATE = po/git-gui.pot
 +ALL_POFILES = $(wildcard po/*.po)
 +ALL_MSGFILES = $(subst .po,.msg,$(ALL_POFILES))
 +
 +$(PO_TEMPLATE): $(SCRIPT_SH) $(ALL_LIBFILES)
 +      $(XGETTEXT) -kmc -LTcl -o $@ $(SCRIPT_SH) $(ALL_LIBFILES)
 +update-po:: $(PO_TEMPLATE)
 +      $(foreach p, $(ALL_POFILES), echo Updating $p ; msgmerge -U $p $(PO_TEMPLATE) ; )
 +$(ALL_MSGFILES): %.msg : %.po
 +      $(QUIET_MSGFMT0)$(MSGFMT) --statistics --tcl $< -l $(basename $(notdir $<)) -d $(dir $@) $(QUIET_MSGFMT1)
 +
  lib/tclIndex: $(ALL_LIBFILES)
        $(QUIET_INDEX)if echo \
          $(foreach p,$(PRELOAD_FILES),source $p\;) \
@@@ -143,7 -126,7 +143,7 @@@ TRACK_VARS = 
        $(subst ','\'',TCL_PATH='$(TCL_PATH_SQ)') \
        $(subst ','\'',TCLTK_PATH='$(TCLTK_PATH_SQ)') \
        $(subst ','\'',gitexecdir='$(gitexecdir_SQ)') \
-       $(subst ','\'',libdir='$(libdir_SQ)') \
+       $(subst ','\'',gg_libdir='$(libdir_SQ)') \
  #end TRACK_VARS
  
  GIT-GUI-VARS: .FORCE-GIT-GUI-VARS
                echo 1>$@ "$$VARS"; \
        fi
  
 -all:: $(ALL_PROGRAMS) lib/tclIndex
 +all:: $(ALL_PROGRAMS) lib/tclIndex $(ALL_MSGFILES)
  
  install: all
        $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
        $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(libdir_SQ)' $(INSTALL_D1)
        $(QUIET)$(INSTALL_R0)lib/tclIndex $(INSTALL_R1) '$(DESTDIR_SQ)$(libdir_SQ)'
        $(QUIET)$(foreach p,$(ALL_LIBFILES), $(INSTALL_R0)$p $(INSTALL_R1) '$(DESTDIR_SQ)$(libdir_SQ)' &&) true
 +      $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(msgsdir_SQ)' $(INSTALL_D1)
 +      $(QUIET)$(foreach p,$(ALL_MSGFILES), $(INSTALL_R0)$p $(INSTALL_R1) '$(DESTDIR_SQ)$(msgsdir_SQ)' &&) true
  
  dist-version:
        @mkdir -p $(TARDIR)
        @echo $(GITGUI_VERSION) > $(TARDIR)/version
  
  clean::
 -      rm -f $(ALL_PROGRAMS) lib/tclIndex
 +      rm -f $(ALL_PROGRAMS) lib/tclIndex po/*.msg
        rm -f GIT-VERSION-FILE GIT-GUI-VARS
  
  .PHONY: all install dist-version clean
diff --combined git-gui.sh
index b3d447e598019eefc3f3d27029b18017a934f724,6d676097a6a3aeecfda3a752b7344dc88094956c..daab7e44bbbb35621bfff12fd7a667e997311528
@@@ -42,24 -42,8 +42,26 @@@ if {[catch {package require Tcl 8.4} er
        exit 1
  }
  
+ rename send {} ; # What an evil concept...
 +######################################################################
 +##
 +## locate our library
 +
 +set oguilib {@@GITGUI_LIBDIR@@}
 +set oguirel {@@GITGUI_RELATIVE@@}
 +if {$oguirel eq {1}} {
 +      set oguilib [file dirname [file dirname [file normalize $argv0]]]
 +      set oguilib [file join $oguilib share git-gui lib]
 +      set oguimsg [file join $oguilib msgs]
 +} elseif {[string match @@* $oguirel]} {
 +      set oguilib [file join [file dirname [file normalize $argv0]] lib]
 +      set oguimsg [file join [file dirname [file normalize $argv0]] po]
 +} else {
 +      set oguimsg [file join $oguilib msgs]
 +}
 +unset oguirel
 +
  ######################################################################
  ##
  ## enable verbose loading?
@@@ -78,16 -62,6 +80,16 @@@ if {![catch {set _verbose $env(GITGUI_V
        }
  }
  
 +######################################################################
 +##
 +## Internationalization (i18n) through msgcat and gettext. See
 +## http://www.gnu.org/software/gettext/manual/html_node/Tcl.html
 +
 +package require msgcat
 +namespace import ::msgcat::mc
 +::msgcat::mcload $oguimsg
 +unset oguimsg
 +
  ######################################################################
  ##
  ## read only globals
@@@ -502,7 -476,7 +504,7 @@@ proc tk_optionMenu {w varName args} 
  set _git  [_which git]
  if {$_git eq {}} {
        catch {wm withdraw .}
 -      error_popup "Cannot find git in PATH."
 +      error_popup [mc "Cannot find git in PATH."]
        exit 1
  }
  
@@@ -529,7 -503,7 +531,7 @@@ if {![regsub {^git version } $_git_vers
                -icon error \
                -type ok \
                -title "git-gui: fatal error" \
 -              -message "Cannot parse Git version string:\n\n$_git_version"
 +              -message [append [mc "Cannot parse Git version string:"] "\n\n$_git_version"]
        exit 1
  }
  
@@@ -546,14 -520,14 +548,14 @@@ if {![regexp {^[1-9]+(\.[0-9]+)+$} $_gi
                -type yesno \
                -default no \
                -title "[appname]: warning" \
 -              -message "Git version cannot be determined.
 +               -message [mc "Git version cannot be determined.
  
 -$_git claims it is version '$_real_git_version'.
 +%s claims it is version '%s'.
  
 -[appname] requires at least Git 1.5.0 or later.
 +%s requires at least Git 1.5.0 or later.
  
 -Assume '$_real_git_version' is version 1.5.0?
 -"] eq {yes}} {
 +Assume '%s' is version 1.5.0?
 +" $_git $_real_git_version [appname] $_real_git_version]] eq {yes}} {
                set _git_version 1.5.0
        } else {
                exit 1
@@@ -623,6 -597,15 +625,6 @@@ You are using [git-version]
  ##
  ## configure our library
  
 -set oguilib {@@GITGUI_LIBDIR@@}
 -set oguirel {@@GITGUI_RELATIVE@@}
 -if {$oguirel eq {1}} {
 -      set oguilib [file dirname [file dirname [file normalize $argv0]]]
 -      set oguilib [file join $oguilib share git-gui lib]
 -} elseif {[string match @@* $oguirel]} {
 -      set oguilib [file join [file dirname [file normalize $argv0]] lib]
 -}
 -
  set idx [file join $oguilib tclIndex]
  if {[catch {set fd [open $idx r]} err]} {
        catch {wm withdraw .}
@@@ -656,7 -639,7 +658,7 @@@ if {$idx ne {}} 
  } else {
        set auto_path [concat [list $oguilib] $auto_path]
  }
 -unset -nocomplain oguirel idx fd
 +unset -nocomplain idx fd
  
  ######################################################################
  ##
@@@ -711,7 -694,7 +713,7 @@@ if {[catch 
                set _prefix [git rev-parse --show-prefix]
        } err]} {
        catch {wm withdraw .}
 -      error_popup "Cannot find the git directory:\n\n$err"
 +      error_popup [append [mc "Cannot find the git directory:"] "\n\n$err"]
        exit 1
  }
  if {![file isdirectory $_gitdir] && [is_Cygwin]} {
  }
  if {![file isdirectory $_gitdir]} {
        catch {wm withdraw .}
 -      error_popup "Git directory not found:\n\n$_gitdir"
 +      error_popup [append [mc "Git directory not found:"] "\n\n$_gitdir"]
        exit 1
  }
  if {$_prefix ne {}} {
  } elseif {![is_enabled bare]} {
        if {[lindex [file split $_gitdir] end] ne {.git}} {
                catch {wm withdraw .}
 -              error_popup "Cannot use funny .git directory:\n\n$_gitdir"
 +              error_popup [append [mc "Cannot use funny .git directory:"] "\n\n$_gitdir"]
                exit 1
        }
        if {[catch {cd [file dirname $_gitdir]} err]} {
                catch {wm withdraw .}
 -              error_popup "No working directory [file dirname $_gitdir]:\n\n$err"
 +              error_popup [append [mc "No working directory"] " [file dirname $_gitdir]:\n\n$err"]
                exit 1
        }
  }
@@@ -885,7 -868,7 +887,7 @@@ proc rescan {after {honor_trustmtime 1}
                rescan_stage2 {} $after
        } else {
                set rescan_active 1
 -              ui_status {Refreshing file status...}
 +              ui_status [mc "Refreshing file status..."]
                set fd_rf [git_read update-index \
                        -q \
                        --unmerged \
@@@ -922,7 -905,7 +924,7 @@@ proc rescan_stage2 {fd after} 
        set buf_rlo {}
  
        set rescan_active 3
 -      ui_status {Scanning for modified files ...}
 +      ui_status [mc "Scanning for modified files ..."]
        set fd_di [git_read diff-index --cached -z [PARENT]]
        set fd_df [git_read diff-files -z]
        set fd_lo [eval git_read ls-files --others -z $ls_others]
@@@ -1088,7 -1071,7 +1090,7 @@@ proc ui_status {msg} 
  }
  
  proc ui_ready {{test {}}} {
 -      $::main_status show {Ready.} $test
 +      $::main_status show [mc "Ready."] $test
  }
  
  proc escape_path {path} {
@@@ -1353,32 -1336,31 +1355,32 @@@ set all_icons(O$ui_workdir) file_plai
  
  set max_status_desc 0
  foreach i {
 -              {__ "Unmodified"}
 -
 -              {_M "Modified, not staged"}
 -              {M_ "Staged for commit"}
 -              {MM "Portions staged for commit"}
 -              {MD "Staged for commit, missing"}
 -
 -              {_O "Untracked, not staged"}
 -              {A_ "Staged for commit"}
 -              {AM "Portions staged for commit"}
 -              {AD "Staged for commit, missing"}
 -
 -              {_D "Missing"}
 -              {D_ "Staged for removal"}
 -              {DO "Staged for removal, still present"}
 -
 -              {U_ "Requires merge resolution"}
 -              {UU "Requires merge resolution"}
 -              {UM "Requires merge resolution"}
 -              {UD "Requires merge resolution"}
 +              {__ {mc "Unmodified"}}
 +
 +              {_M {mc "Modified, not staged"}}
 +              {M_ {mc "Staged for commit"}}
 +              {MM {mc "Portions staged for commit"}}
 +              {MD {mc "Staged for commit, missing"}}
 +
 +              {_O {mc "Untracked, not staged"}}
 +              {A_ {mc "Staged for commit"}}
 +              {AM {mc "Portions staged for commit"}}
 +              {AD {mc "Staged for commit, missing"}}
 +
 +              {_D {mc "Missing"}}
 +              {D_ {mc "Staged for removal"}}
 +              {DO {mc "Staged for removal, still present"}}
 +
 +              {U_ {mc "Requires merge resolution"}}
 +              {UU {mc "Requires merge resolution"}}
 +              {UM {mc "Requires merge resolution"}}
 +              {UD {mc "Requires merge resolution"}}
        } {
 -      if {$max_status_desc < [string length [lindex $i 1]]} {
 -              set max_status_desc [string length [lindex $i 1]]
 +      set text [eval [lindex $i 1]]
 +      if {$max_status_desc < [string length $text]} {
 +              set max_status_desc [string length $text]
        }
 -      set all_descs([lindex $i 0]) [lindex $i 1]
 +      set all_descs([lindex $i 0]) $text
  }
  unset i
  
@@@ -1417,7 -1399,7 +1419,7 @@@ proc incr_font_size {font {amt 1}} 
  ##
  ## ui commands
  
 -set starting_gitk_msg {Starting gitk... please wait...}
 +set starting_gitk_msg [mc "Starting gitk... please wait..."]
  
  proc do_gitk {revs} {
        # -- Always start gitk through whatever we were loaded with.  This
        set exe [file join [file dirname $::_git] gitk]
        set cmd [list [info nameofexecutable] $exe]
        if {! [file exists $exe]} {
 -              error_popup "Unable to start gitk:\n\n$exe does not exist"
 +              error_popup [mc "Unable to start gitk:\n\n%s does not exist" $exe]
        } else {
                eval exec $cmd $revs &
                ui_status $::starting_gitk_msg
@@@ -1643,7 -1625,7 +1645,7 @@@ proc apply_config {} 
                                font configure $font $cn $cv
                        }
                        } err]} {
 -                      error_popup "Invalid font specified in gui.$name:\n\n$err"
 +                      error_popup [append [mc "Invalid font specified in %s:" "gui.$name"] "\n\n$err"]
                }
                foreach {cn cv} [font configure $font] {
                        font configure ${font}bold $cn $cv
@@@ -1668,8 -1650,8 +1670,8 @@@ set default_config(gui.newbranchtemplat
  set default_config(gui.fontui) [font configure font_ui]
  set default_config(gui.fontdiff) [font configure font_diff]
  set font_descs {
 -      {fontui   font_ui   {Main Font}}
 -      {fontdiff font_diff {Diff/Console Font}}
 +      {fontui   font_ui   {mc "Main Font"}}
 +      {fontdiff font_diff {mc "Diff/Console Font"}}
  }
  load_config 0
  apply_config
@@@ -1683,18 -1665,18 +1685,18 @@@ set ui_comm {
  # -- Menu Bar
  #
  menu .mbar -tearoff 0
 -.mbar add cascade -label Repository -menu .mbar.repository
 -.mbar add cascade -label Edit -menu .mbar.edit
 +.mbar add cascade -label [mc Repository] -menu .mbar.repository
 +.mbar add cascade -label [mc Edit] -menu .mbar.edit
  if {[is_enabled branch]} {
 -      .mbar add cascade -label Branch -menu .mbar.branch
 +      .mbar add cascade -label [mc Branch] -menu .mbar.branch
  }
  if {[is_enabled multicommit] || [is_enabled singlecommit]} {
 -      .mbar add cascade -label Commit -menu .mbar.commit
 +      .mbar add cascade -label [mc Commit] -menu .mbar.commit
  }
  if {[is_enabled transport]} {
 -      .mbar add cascade -label Merge -menu .mbar.merge
 -      .mbar add cascade -label Fetch -menu .mbar.fetch
 -      .mbar add cascade -label Push -menu .mbar.push
 +      .mbar add cascade -label [mc Merge] -menu .mbar.merge
 +      .mbar add cascade -label [mc Fetch] -menu .mbar.fetch
 +      .mbar add cascade -label [mc Push] -menu .mbar.push
  }
  . configure -menu .mbar
  
  menu .mbar.repository
  
  .mbar.repository add command \
 -      -label {Browse Current Branch's Files} \
 +      -label [mc "Browse Current Branch's Files"] \
        -command {browser::new $current_branch}
  set ui_browse_current [.mbar.repository index last]
  .mbar.repository add command \
 -      -label {Browse Branch Files...} \
 +      -label [mc "Browse Branch Files..."] \
        -command browser_open::dialog
  .mbar.repository add separator
  
  .mbar.repository add command \
 -      -label {Visualize Current Branch's History} \
 +      -label [mc "Visualize Current Branch's History"] \
        -command {do_gitk $current_branch}
  set ui_visualize_current [.mbar.repository index last]
  .mbar.repository add command \
 -      -label {Visualize All Branch History} \
 +      -label [mc "Visualize All Branch History"] \
        -command {do_gitk --all}
  .mbar.repository add separator
  
  proc current_branch_write {args} {
        global current_branch
        .mbar.repository entryconf $::ui_browse_current \
 -              -label "Browse $current_branch's Files"
 +              -label [mc "Browse %s's Files" $current_branch]
        .mbar.repository entryconf $::ui_visualize_current \
 -              -label "Visualize $current_branch's History"
 +              -label [mc "Visualize %s's History" $current_branch]
  }
  trace add variable current_branch write current_branch_write
  
  if {[is_enabled multicommit]} {
 -      .mbar.repository add command -label {Database Statistics} \
 +      .mbar.repository add command -label [mc "Database Statistics"] \
                -command do_stats
  
 -      .mbar.repository add command -label {Compress Database} \
 +      .mbar.repository add command -label [mc "Compress Database"] \
                -command do_gc
  
 -      .mbar.repository add command -label {Verify Database} \
 +      .mbar.repository add command -label [mc "Verify Database"] \
                -command do_fsck_objects
  
        .mbar.repository add separator
  
        if {[is_Cygwin]} {
                .mbar.repository add command \
 -                      -label {Create Desktop Icon} \
 +                      -label [mc "Create Desktop Icon"] \
                        -command do_cygwin_shortcut
        } elseif {[is_Windows]} {
                .mbar.repository add command \
 -                      -label {Create Desktop Icon} \
 +                      -label [mc "Create Desktop Icon"] \
                        -command do_windows_shortcut
        } elseif {[is_MacOSX]} {
                .mbar.repository add command \
 -                      -label {Create Desktop Icon} \
 +                      -label [mc "Create Desktop Icon"] \
                        -command do_macosx_app
        }
  }
  
 -.mbar.repository add command -label Quit \
 +.mbar.repository add command -label [mc Quit] \
        -command do_quit \
        -accelerator $M1T-Q
  
  # -- Edit Menu
  #
  menu .mbar.edit
 -.mbar.edit add command -label Undo \
 +.mbar.edit add command -label [mc Undo] \
        -command {catch {[focus] edit undo}} \
        -accelerator $M1T-Z
 -.mbar.edit add command -label Redo \
 +.mbar.edit add command -label [mc Redo] \
        -command {catch {[focus] edit redo}} \
        -accelerator $M1T-Y
  .mbar.edit add separator
 -.mbar.edit add command -label Cut \
 +.mbar.edit add command -label [mc Cut] \
        -command {catch {tk_textCut [focus]}} \
        -accelerator $M1T-X
 -.mbar.edit add command -label Copy \
 +.mbar.edit add command -label [mc Copy] \
        -command {catch {tk_textCopy [focus]}} \
        -accelerator $M1T-C
 -.mbar.edit add command -label Paste \
 +.mbar.edit add command -label [mc Paste] \
        -command {catch {tk_textPaste [focus]; [focus] see insert}} \
        -accelerator $M1T-V
 -.mbar.edit add command -label Delete \
 +.mbar.edit add command -label [mc Delete] \
        -command {catch {[focus] delete sel.first sel.last}} \
        -accelerator Del
  .mbar.edit add separator
 -.mbar.edit add command -label {Select All} \
 +.mbar.edit add command -label [mc "Select All"] \
        -command {catch {[focus] tag add sel 0.0 end}} \
        -accelerator $M1T-A
  
  if {[is_enabled branch]} {
        menu .mbar.branch
  
 -      .mbar.branch add command -label {Create...} \
 +      .mbar.branch add command -label [mc "Create..."] \
                -command branch_create::dialog \
                -accelerator $M1T-N
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
  
 -      .mbar.branch add command -label {Checkout...} \
 +      .mbar.branch add command -label [mc "Checkout..."] \
                -command branch_checkout::dialog \
                -accelerator $M1T-O
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
  
 -      .mbar.branch add command -label {Rename...} \
 +      .mbar.branch add command -label [mc "Rename..."] \
                -command branch_rename::dialog
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
  
 -      .mbar.branch add command -label {Delete...} \
 +      .mbar.branch add command -label [mc "Delete..."] \
                -command branch_delete::dialog
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
  
 -      .mbar.branch add command -label {Reset...} \
 +      .mbar.branch add command -label [mc "Reset..."] \
                -command merge::reset_hard
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
@@@ -1826,7 -1808,7 +1828,7 @@@ if {[is_enabled multicommit] || [is_ena
        menu .mbar.commit
  
        .mbar.commit add radiobutton \
 -              -label {New Commit} \
 +              -label [mc "New Commit"] \
                -command do_select_commit_type \
                -variable selected_commit_type \
                -value new
                [list .mbar.commit entryconf [.mbar.commit index last] -state]
  
        .mbar.commit add radiobutton \
 -              -label {Amend Last Commit} \
 +              -label [mc "Amend Last Commit"] \
                -command do_select_commit_type \
                -variable selected_commit_type \
                -value amend
  
        .mbar.commit add separator
  
 -      .mbar.commit add command -label Rescan \
 +      .mbar.commit add command -label [mc Rescan] \
                -command do_rescan \
                -accelerator F5
        lappend disable_on_lock \
                [list .mbar.commit entryconf [.mbar.commit index last] -state]
  
 -      .mbar.commit add command -label {Stage To Commit} \
 +      .mbar.commit add command -label [mc "Stage To Commit"] \
                -command do_add_selection
        lappend disable_on_lock \
                [list .mbar.commit entryconf [.mbar.commit index last] -state]
  
 -      .mbar.commit add command -label {Stage Changed Files To Commit} \
 +      .mbar.commit add command -label [mc "Stage Changed Files To Commit"] \
                -command do_add_all \
                -accelerator $M1T-I
        lappend disable_on_lock \
                [list .mbar.commit entryconf [.mbar.commit index last] -state]
  
 -      .mbar.commit add command -label {Unstage From Commit} \
 +      .mbar.commit add command -label [mc "Unstage From Commit"] \
                -command do_unstage_selection
        lappend disable_on_lock \
                [list .mbar.commit entryconf [.mbar.commit index last] -state]
  
 -      .mbar.commit add command -label {Revert Changes} \
 +      .mbar.commit add command -label [mc "Revert Changes"] \
                -command do_revert_selection
        lappend disable_on_lock \
                [list .mbar.commit entryconf [.mbar.commit index last] -state]
  
        .mbar.commit add separator
  
 -      .mbar.commit add command -label {Sign Off} \
 +      .mbar.commit add command -label [mc "Sign Off"] \
                -command do_signoff \
                -accelerator $M1T-S
  
 -      .mbar.commit add command -label Commit \
 +      .mbar.commit add command -label [mc Commit] \
                -command do_commit \
                -accelerator $M1T-Return
        lappend disable_on_lock \
  #
  if {[is_enabled branch]} {
        menu .mbar.merge
 -      .mbar.merge add command -label {Local Merge...} \
 +      .mbar.merge add command -label [mc "Local Merge..."] \
                -command merge::dialog \
                -accelerator $M1T-M
        lappend disable_on_lock \
                [list .mbar.merge entryconf [.mbar.merge index last] -state]
 -      .mbar.merge add command -label {Abort Merge...} \
 +      .mbar.merge add command -label [mc "Abort Merge..."] \
                -command merge::reset_hard
        lappend disable_on_lock \
                [list .mbar.merge entryconf [.mbar.merge index last] -state]
@@@ -1904,38 -1886,38 +1906,38 @@@ if {[is_enabled transport]} 
        menu .mbar.fetch
  
        menu .mbar.push
 -      .mbar.push add command -label {Push...} \
 +      .mbar.push add command -label [mc "Push..."] \
                -command do_push_anywhere \
                -accelerator $M1T-P
 -      .mbar.push add command -label {Delete...} \
 +      .mbar.push add command -label [mc "Delete..."] \
                -command remote_branch_delete::dialog
  }
  
  if {[is_MacOSX]} {
        # -- Apple Menu (Mac OS X only)
        #
 -      .mbar add cascade -label Apple -menu .mbar.apple
 +      .mbar add cascade -label [mc Apple] -menu .mbar.apple
        menu .mbar.apple
  
 -      .mbar.apple add command -label "About [appname]" \
 +      .mbar.apple add command -label [mc "About %s" [appname]] \
                -command do_about
 -      .mbar.apple add command -label "Options..." \
 +      .mbar.apple add command -label [mc "Options..."] \
                -command do_options
  } else {
        # -- Edit Menu
        #
        .mbar.edit add separator
 -      .mbar.edit add command -label {Options...} \
 +      .mbar.edit add command -label [mc "Options..."] \
                -command do_options
  }
  
  # -- Help Menu
  #
 -.mbar add cascade -label Help -menu .mbar.help
 +.mbar add cascade -label [mc Help] -menu .mbar.help
  menu .mbar.help
  
  if {![is_MacOSX]} {
 -      .mbar.help add command -label "About [appname]" \
 +      .mbar.help add command -label [mc "About %s" [appname]] \
                -command do_about
  }
  
@@@ -1972,7 -1954,7 +1974,7 @@@ if {[file isfile $doc_path]} 
  }
  
  if {$browser ne {}} {
 -      .mbar.help add command -label {Online Documentation} \
 +      .mbar.help add command -label [mc "Online Documentation"] \
                -command [list exec $browser $doc_url &]
  }
  unset browser doc_path doc_url
@@@ -2094,7 -2076,7 +2096,7 @@@ frame .branch 
        -borderwidth 1 \
        -relief sunken
  label .branch.l1 \
 -      -text {Current Branch:} \
 +      -text [mc "Current Branch:"] \
        -anchor w \
        -justify left
  label .branch.cb \
@@@ -2115,7 -2097,7 +2117,7 @@@ pack .vpane -anchor n -side top -fill b
  # -- Index File List
  #
  frame .vpane.files.index -height 100 -width 200
 -label .vpane.files.index.title -text {Staged Changes (Will Be Committed)} \
 +label .vpane.files.index.title -text [mc "Staged Changes (Will Be Committed)"] \
        -background lightgreen
  text $ui_index -background white -borderwidth 0 \
        -width 20 -height 10 \
@@@ -2135,7 -2117,7 +2137,7 @@@ pack $ui_index -side left -fill both -e
  # -- Working Directory File List
  #
  frame .vpane.files.workdir -height 100 -width 200
 -label .vpane.files.workdir.title -text {Unstaged Changes (Will Not Be Committed)} \
 +label .vpane.files.workdir.title -text [mc "Unstaged Changes (Will Not Be Committed)"] \
        -background lightsalmon
  text $ui_workdir -background white -borderwidth 0 \
        -width 20 -height 10 \
@@@ -2176,29 -2158,29 +2178,29 @@@ label .vpane.lower.commarea.buttons.l -
  pack .vpane.lower.commarea.buttons.l -side top -fill x
  pack .vpane.lower.commarea.buttons -side left -fill y
  
 -button .vpane.lower.commarea.buttons.rescan -text {Rescan} \
 +button .vpane.lower.commarea.buttons.rescan -text [mc Rescan] \
        -command do_rescan
  pack .vpane.lower.commarea.buttons.rescan -side top -fill x
  lappend disable_on_lock \
        {.vpane.lower.commarea.buttons.rescan conf -state}
  
 -button .vpane.lower.commarea.buttons.incall -text {Stage Changed} \
 +button .vpane.lower.commarea.buttons.incall -text [mc "Stage Changed"] \
        -command do_add_all
  pack .vpane.lower.commarea.buttons.incall -side top -fill x
  lappend disable_on_lock \
        {.vpane.lower.commarea.buttons.incall conf -state}
  
 -button .vpane.lower.commarea.buttons.signoff -text {Sign Off} \
 +button .vpane.lower.commarea.buttons.signoff -text [mc "Sign Off"] \
        -command do_signoff
  pack .vpane.lower.commarea.buttons.signoff -side top -fill x
  
 -button .vpane.lower.commarea.buttons.commit -text {Commit} \
 +button .vpane.lower.commarea.buttons.commit -text [mc Commit] \
        -command do_commit
  pack .vpane.lower.commarea.buttons.commit -side top -fill x
  lappend disable_on_lock \
        {.vpane.lower.commarea.buttons.commit conf -state}
  
 -button .vpane.lower.commarea.buttons.push -text {Push} \
 +button .vpane.lower.commarea.buttons.push -text [mc Push] \
        -command do_push_anywhere
  pack .vpane.lower.commarea.buttons.push -side top -fill x
  
@@@ -2209,14 -2191,14 +2211,14 @@@ frame .vpane.lower.commarea.buffer.head
  set ui_comm .vpane.lower.commarea.buffer.t
  set ui_coml .vpane.lower.commarea.buffer.header.l
  radiobutton .vpane.lower.commarea.buffer.header.new \
 -      -text {New Commit} \
 +      -text [mc "New Commit"] \
        -command do_select_commit_type \
        -variable selected_commit_type \
        -value new
  lappend disable_on_lock \
        [list .vpane.lower.commarea.buffer.header.new conf -state]
  radiobutton .vpane.lower.commarea.buffer.header.amend \
 -      -text {Amend Last Commit} \
 +      -text [mc "Amend Last Commit"] \
        -command do_select_commit_type \
        -variable selected_commit_type \
        -value amend
@@@ -2228,12 -2210,12 +2230,12 @@@ label $ui_coml 
  proc trace_commit_type {varname args} {
        global ui_coml commit_type
        switch -glob -- $commit_type {
 -      initial       {set txt {Initial Commit Message:}}
 -      amend         {set txt {Amended Commit Message:}}
 -      amend-initial {set txt {Amended Initial Commit Message:}}
 -      amend-merge   {set txt {Amended Merge Commit Message:}}
 -      merge         {set txt {Merge Commit Message:}}
 -      *             {set txt {Commit Message:}}
 +      initial       {set txt [mc "Initial Commit Message:"]}
 +      amend         {set txt [mc "Amended Commit Message:"]}
 +      amend-initial {set txt [mc "Amended Initial Commit Message:"]}
 +      amend-merge   {set txt [mc "Amended Merge Commit Message:"]}
 +      merge         {set txt [mc "Merge Commit Message:"]}
 +      *             {set txt [mc "Commit Message:"]}
        }
        $ui_coml conf -text $txt
  }
@@@ -2262,23 -2244,23 +2264,23 @@@ pack .vpane.lower.commarea.buffer -sid
  set ctxm .vpane.lower.commarea.buffer.ctxm
  menu $ctxm -tearoff 0
  $ctxm add command \
 -      -label {Cut} \
 +      -label [mc Cut] \
        -command {tk_textCut $ui_comm}
  $ctxm add command \
 -      -label {Copy} \
 +      -label [mc Copy] \
        -command {tk_textCopy $ui_comm}
  $ctxm add command \
 -      -label {Paste} \
 +      -label [mc Paste] \
        -command {tk_textPaste $ui_comm}
  $ctxm add command \
 -      -label {Delete} \
 +      -label [mc Delete] \
        -command {$ui_comm delete sel.first sel.last}
  $ctxm add separator
  $ctxm add command \
 -      -label {Select All} \
 +      -label [mc "Select All"] \
        -command {focus $ui_comm;$ui_comm tag add sel 0.0 end}
  $ctxm add command \
 -      -label {Copy All} \
 +      -label [mc "Copy All"] \
        -command {
                $ui_comm tag add sel 0.0 end
                tk_textCopy $ui_comm
        }
  $ctxm add separator
  $ctxm add command \
 -      -label {Sign Off} \
 +      -label [mc "Sign Off"] \
        -command do_signoff
  bind_button3 $ui_comm "tk_popup $ctxm %X %Y"
  
@@@ -2302,7 -2284,7 +2304,7 @@@ proc trace_current_diff_path {varname a
        } else {
                set p $current_diff_path
                set s [mapdesc [lindex $file_states($p) 0] $p]
 -              set f {File:}
 +              set f [mc "File:"]
                set p [escape_path $p]
                set o normal
        }
@@@ -2336,7 -2318,7 +2338,7 @@@ pack .vpane.lower.diff.header.path -fil
  set ctxm .vpane.lower.diff.header.ctxm
  menu $ctxm -tearoff 0
  $ctxm add command \
 -      -label {Copy} \
 +      -label [mc Copy] \
        -command {
                clipboard clear
                clipboard append \
@@@ -2404,19 -2386,19 +2406,19 @@@ $ui_diff tag raise se
  set ctxm .vpane.lower.diff.body.ctxm
  menu $ctxm -tearoff 0
  $ctxm add command \
 -      -label {Refresh} \
 +      -label [mc Refresh] \
        -command reshow_diff
  lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
  $ctxm add command \
 -      -label {Copy} \
 +      -label [mc Copy] \
        -command {tk_textCopy $ui_diff}
  lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
  $ctxm add command \
 -      -label {Select All} \
 +      -label [mc "Select All"] \
        -command {focus $ui_diff;$ui_diff tag add sel 0.0 end}
  lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
  $ctxm add command \
 -      -label {Copy All} \
 +      -label [mc "Copy All"] \
        -command {
                $ui_diff tag add sel 0.0 end
                tk_textCopy $ui_diff
  lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
  $ctxm add separator
  $ctxm add command \
 -      -label {Apply/Reverse Hunk} \
 +      -label [mc "Apply/Reverse Hunk"] \
        -command {apply_hunk $cursorX $cursorY}
  set ui_diff_applyhunk [$ctxm index last]
  lappend diff_actions [list $ctxm entryconf $ui_diff_applyhunk -state]
  $ctxm add separator
  $ctxm add command \
 -      -label {Decrease Font Size} \
 +      -label [mc "Decrease Font Size"] \
        -command {incr_font_size font_diff -1}
  lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
  $ctxm add command \
 -      -label {Increase Font Size} \
 +      -label [mc "Increase Font Size"] \
        -command {incr_font_size font_diff 1}
  lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
  $ctxm add separator
  $ctxm add command \
 -      -label {Show Less Context} \
 +      -label [mc "Show Less Context"] \
        -command {if {$repo_config(gui.diffcontext) >= 1} {
                incr repo_config(gui.diffcontext) -1
                reshow_diff
        }}
  lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
  $ctxm add command \
 -      -label {Show More Context} \
 +      -label [mc "Show More Context"] \
        -command {if {$repo_config(gui.diffcontext) < 99} {
                incr repo_config(gui.diffcontext)
                reshow_diff
        }}
  lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
  $ctxm add separator
 -$ctxm add command -label {Options...} \
 +$ctxm add command -label [mc "Options..."] \
        -command do_options
  proc popup_diff_menu {ctxm x y X Y} {
        global current_diff_path file_states
        set ::cursorX $x
        set ::cursorY $y
        if {$::ui_index eq $::current_diff_side} {
 -              set l "Unstage Hunk From Commit"
 +              set l [mc "Unstage Hunk From Commit"]
        } else {
 -              set l "Stage Hunk For Commit"
 +              set l [mc "Stage Hunk For Commit"]
        }
        if {$::is_3way_diff
                || $current_diff_path eq {}
@@@ -2482,7 -2464,7 +2484,7 @@@ bind_button3 $ui_diff [list popup_diff_
  #
  set main_status [::status_bar::new .status]
  pack .status -anchor w -side bottom -fill x
 -$main_status show {Initializing...}
 +$main_status show [mc "Initializing..."]
  
  # -- Load geometry
  #
diff --combined lib/index.tcl
index b3f5e17d1fa6eaa2d2bd99ea795f91bf5aacd449,cbbce13a77587fc121659fd0c3c76ec261bcb09a..78e2101adaa2bc6c80e7d57878e741fbe86a67f1
@@@ -13,7 -13,8 +13,8 @@@ proc update_indexinfo {msg pathList aft
        if {$batch > 25} {set batch 25}
  
        ui_status [format \
-               "$msg... %i/%i files (%.2f%%)" \
+               "%s... %i/%i files (%.2f%%)" \
+               $msg \
                $update_index_cp \
                $totalCnt \
                0.0]
@@@ -68,7 -69,8 +69,8 @@@ proc write_update_indexinfo {fd pathLis
        }
  
        ui_status [format \
-               "$msg... %i/%i files (%.2f%%)" \
+               "%s... %i/%i files (%.2f%%)" \
+               $msg \
                $update_index_cp \
                $totalCnt \
                [expr {100.0 * $update_index_cp / $totalCnt}]]
@@@ -86,7 -88,8 +88,8 @@@ proc update_index {msg pathList after} 
        if {$batch > 25} {set batch 25}
  
        ui_status [format \
-               "$msg... %i/%i files (%.2f%%)" \
+               "%s... %i/%i files (%.2f%%)" \
+               $msg \
                $update_index_cp \
                $totalCnt \
                0.0]
@@@ -145,7 -148,8 +148,8 @@@ proc write_update_index {fd pathList to
        }
  
        ui_status [format \
-               "$msg... %i/%i files (%.2f%%)" \
+               "%s... %i/%i files (%.2f%%)" \
+               $msg \
                $update_index_cp \
                $totalCnt \
                [expr {100.0 * $update_index_cp / $totalCnt}]]
@@@ -163,7 -167,8 +167,8 @@@ proc checkout_index {msg pathList after
        if {$batch > 25} {set batch 25}
  
        ui_status [format \
-               "$msg... %i/%i files (%.2f%%)" \
+               "%s... %i/%i files (%.2f%%)" \
+               $msg
                $update_index_cp \
                $totalCnt \
                0.0]
@@@ -218,7 -223,8 +223,8 @@@ proc write_checkout_index {fd pathList 
        }
  
        ui_status [format \
-               "$msg... %i/%i files (%.2f%%)" \
+               "%s... %i/%i files (%.2f%%)" \
+               $msg \
                $update_index_cp \
                $totalCnt \
                [expr {100.0 * $update_index_cp / $totalCnt}]]
@@@ -345,35 -351,26 +351,35 @@@ proc revert_helper {txt paths} 
                }
        }
  
 +
 +      # Split question between singular and plural cases, because
 +      # such distinction is needed in some languages. Previously, the
 +      # code used "Revert changes in" for both, but that can't work
 +      # in languages where 'in' must be combined with word from
 +      # rest of string (in diffrent way for both cases of course).
 +      #
 +      # FIXME: Unfortunately, even that isn't enough in some languages
 +      # as they have quite complex plural-form rules. Unfortunately,
 +      # msgcat doesn't seem to support that kind of string translation.
 +      #
        set n [llength $pathList]
        if {$n == 0} {
                unlock_index
                return
        } elseif {$n == 1} {
 -              set s "[short_path [lindex $pathList]]"
 +              set query [mc "Revert changes in file %s?" [short_path [lindex $pathList]]]
        } else {
 -              set s "these $n files"
 +              set query [mc "Revert changes in these %i files?" $n]
        }
  
        set reply [tk_dialog \
                .confirm_revert \
                "[appname] ([reponame])" \
 -              "Revert changes in $s?
 -
 -Any unstaged changes will be permanently lost by the revert." \
 +              [mc "Any unstaged changes will be permanently lost by the revert."] \
                question \
                1 \
 -              {Do Nothing} \
 -              {Revert Changes} \
 +              [mc "Do Nothing"] \
 +              [mc "Revert Changes"] \
                ]
        if {$reply == 1} {
                checkout_index \