summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2018-08-16 21:46:42 +1000
committerGitHub <noreply@github.com>2018-08-16 21:46:42 +1000
commit090537a1f175f4320885486199752dc9508faca4 (patch)
tree4fd0ee87031f4171b3120ab3682e3ffdd5f8cc2c
parent59ab38fff6bcfe8ec25c1cf658833cb8d0b69440 (diff)
parentfcf616bd62a71e3ae3fac9ef93d02e20e8355c0b (diff)
Merge pull request #137 from mjarkk/master
Added a view basic translation functions and translation file
-rw-r--r--pkg/app/app.go10
-rw-r--r--pkg/commands/os.go11
-rw-r--r--pkg/gui/branches_panel.go47
-rw-r--r--pkg/gui/commit_message_panel.go19
-rw-r--r--pkg/gui/commits_panel.go40
-rw-r--r--pkg/gui/confirmation_panel.go21
-rw-r--r--pkg/gui/files_panel.go95
-rw-r--r--pkg/gui/gui.go63
-rw-r--r--pkg/gui/merge_panel.go10
-rw-r--r--pkg/gui/stash_panel.go26
-rw-r--r--pkg/gui/view_helpers.go34
-rw-r--r--pkg/i18n/dutch.go291
-rw-r--r--pkg/i18n/english.go299
-rw-r--r--pkg/i18n/i18n.go84
14 files changed, 910 insertions, 140 deletions
diff --git a/pkg/app/app.go b/pkg/app/app.go
index d558ed250..3e227a395 100644
--- a/pkg/app/app.go
+++ b/pkg/app/app.go
@@ -9,6 +9,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui"
+ "github.com/jesseduffield/lazygit/pkg/i18n"
)
// App struct
@@ -20,6 +21,7 @@ type App struct {
OSCommand *commands.OSCommand
GitCommand *commands.GitCommand
Gui *gui.Gui
+ Tr *i18n.Localizer
}
func newLogger(config config.AppConfigurer) *logrus.Logger {
@@ -48,11 +50,17 @@ func NewApp(config config.AppConfigurer) (*App, error) {
if err != nil {
return nil, err
}
+
+ app.Tr, err = i18n.NewLocalizer(app.Log)
+ if err != nil {
+ return nil, err
+ }
+
app.GitCommand, err = commands.NewGitCommand(app.Log, app.OSCommand)
if err != nil {
return nil, err
}
- app.Gui, err = gui.NewGui(app.Log, app.GitCommand, app.OSCommand, config.GetVersion())
+ app.Gui, err = gui.NewGui(app.Log, app.GitCommand, app.OSCommand, app.Tr, config.GetVersion())
if err != nil {
return nil, err
}
diff --git a/pkg/commands/os.go b/pkg/commands/os.go
index 9f9819a5a..d4ea75e74 100644
--- a/pkg/commands/os.go
+++ b/pkg/commands/os.go
@@ -14,13 +14,6 @@ import (
gitconfig "github.com/tcnksm/go-gitconfig"
)
-var (
- // ErrNoOpenCommand : When we don't know which command to use to open a file
- ErrNoOpenCommand = errors.New("Unsure what command to use to open this file")
- // ErrNoEditorDefined : When we can't find an editor to edit a file
- ErrNoEditorDefined = errors.New("No editor defined in $VISUAL, $EDITOR, or git config")
-)
-
// Platform stores the os state
type Platform struct {
os string
@@ -113,7 +106,7 @@ func (c *OSCommand) GetOpenCommand() (string, string, error) {
return name, trail, nil
}
}
- return "", "", ErrNoOpenCommand
+ return "", "", errors.New("Unsure what command to use to open this file")
}
// VsCodeOpenFile opens the file in code, with the -r flag to open in the
@@ -157,7 +150,7 @@ func (c *OSCommand) EditFile(filename string) (*exec.Cmd, error) {
}
}
if editor == "" {
- return nil, ErrNoEditorDefined
+ return nil, errors.New("No editor defined in $VISUAL, $EDITOR, or git config")
}
return c.PrepareSubProcess(editor, filename)
}
diff --git a/pkg/gui/branches_panel.go b/pkg/gui/branches_panel.go
index c4786d39f..67e0ceb07 100644
--- a/pkg/gui/branches_panel.go
+++ b/pkg/gui/branches_panel.go
@@ -12,7 +12,7 @@ import (
func (gui *Gui) handleBranchPress(g *gocui.Gui, v *gocui.View) error {
index := gui.getItemPosition(v)
if index == 0 {
- return gui.createErrorPanel(g, "You have already checked out this branch")
+ return gui.createErrorPanel(g, gui.Tr.SLocalize("AlreadyCheckedOutBranch"))
}
branch := gui.getSelectedBranch(v)
if err := gui.GitCommand.Checkout(branch.Name, false); err != nil {
@@ -23,7 +23,9 @@ func (gui *Gui) handleBranchPress(g *gocui.Gui, v *gocui.View) error {
func (gui *Gui) handleForceCheckout(g *gocui.Gui, v *gocui.View) error {
branch := gui.getSelectedBranch(v)
- return gui.createConfirmationPanel(g, v, "Force Checkout Branch", "Are you sure you want force checkout? You will lose all local changes", func(g *gocui.Gui, v *gocui.View) error {
+ message := gui.Tr.SLocalize("SureForceCheckout")
+ title := gui.Tr.SLocalize("ForceCheckoutBranch")
+ return gui.createConfirmationPanel(g, v, title, message, func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.Checkout(branch.Name, true); err != nil {
gui.createErrorPanel(g, err.Error())
}
@@ -32,7 +34,7 @@ func (gui *Gui) handleForceCheckout(g *gocui.Gui, v *gocui.View) error {
}
func (gui *Gui) handleCheckoutByName(g *gocui.Gui, v *gocui.View) error {
- gui.createPromptPanel(g, v, "Branch Name:", func(g *gocui.Gui, v *gocui.View) error {
+ gui.createPromptPanel(g, v, gui.Tr.SLocalize("BranchName")+":", func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.Checkout(gui.trimmedContent(v), false); err != nil {
return gui.createErrorPanel(g, err.Error())
}
@@ -43,7 +45,13 @@ func (gui *Gui) handleCheckoutByName(g *gocui.Gui, v *gocui.View) error {
func (gui *Gui) handleNewBranch(g *gocui.Gui, v *gocui.View) error {
branch := gui.State.Branches[0]
- gui.createPromptPanel(g, v, "New Branch Name (Branch is off of "+branch.Name+")", func(g *gocui.Gui, v *gocui.View) error {
+ message := gui.Tr.TemplateLocalize(
+ "NewBranchNameBranchOff",
+ Teml{
+ "branchName": branch.Name,
+ },
+ )
+ gui.createPromptPanel(g, v, message, func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.NewBranch(gui.trimmedContent(v)); err != nil {
return gui.createErrorPanel(g, err.Error())
}
@@ -57,9 +65,16 @@ func (gui *Gui) handleDeleteBranch(g *gocui.Gui, v *gocui.View) error {
checkedOutBranch := gui.State.Branches[0]
selectedBranch := gui.getSelectedBranch(v)
if checkedOutBranch.Name == selectedBranch.Name {
- return gui.createErrorPanel(g, "You cannot delete the checked out branch!")
+ return gui.createErrorPanel(g, gui.Tr.SLocalize("CantDeleteCheckOutBranch"))
}
- return gui.createConfirmationPanel(g, v, "Delete Branch", "Are you sure you want delete the branch "+selectedBranch.Name+" ?", func(g *gocui.Gui, v *gocui.View) error {
+ message := gui.Tr.TemplateLocalize(
+ "DeleteBranchMessage",
+ Teml{
+ "selectedBranchName": selectedBranch.Name,
+ },
+ )
+ title := gui.Tr.SLocalize("DeleteBranch")
+ return gui.createConfirmationPanel(g, v, title, message, func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.DeleteBranch(selectedBranch.Name); err != nil {
return gui.createErrorPanel(g, err.Error())
}
@@ -72,7 +87,7 @@ func (gui *Gui) handleMerge(g *gocui.Gui, v *gocui.View) error {
selectedBranch := gui.getSelectedBranch(v)
defer gui.refreshSidePanels(g)
if checkedOutBranch.Name == selectedBranch.Name {
- return gui.createErrorPanel(g, "You cannot merge a branch into itself")
+ return gui.createErrorPanel(g, gui.Tr.SLocalize("CantMergeBranchIntoItself"))
}
if err := gui.GitCommand.Merge(selectedBranch.Name); err != nil {
return gui.createErrorPanel(g, err.Error())
@@ -87,13 +102,13 @@ func (gui *Gui) getSelectedBranch(v *gocui.View) commands.Branch {
func (gui *Gui) renderBranchesOptions(g *gocui.Gui) error {
return gui.renderOptionsMap(g, map[string]string{
- "space": "checkout",
- "f": "force checkout",
- "m": "merge",
- "c": "checkout by name",
- "n": "new branch",
- "d": "delete branch",
- "← → ↑ ↓": "navigate",
+ "space": gui.Tr.SLocalize("checkout"),
+ "f": gui.Tr.SLocalize("forceCheckout"),
+ "m": gui.Tr.SLocalize("merge"),
+ "c": gui.Tr.SLocalize("checkoutByName"),
+ "n": gui.Tr.SLocalize("newBranch"),
+ "d": gui.Tr.SLocalize("deleteBranch"),
+ "← → ↑ ↓": gui.Tr.SLocalize("navigate"),
})
}
@@ -104,13 +119,13 @@ func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error {
}
// This really shouldn't happen: there should always be a master branch
if len(gui.State.Branches) == 0 {
- return gui.renderString(g, "main", "No branches for this repo")
+ return gui.renderString(g, "main", gui.Tr.SLocalize("NoBranchesThisRepo"))
}
go func() {
branch := gui.getSelectedBranch(v)
diff, err := gui.GitCommand.GetBranchGraph(branch.Name)
if err != nil && strings.HasPrefix(diff, "fatal: ambiguous argument") {
- diff = "There is no tracking for this branch"
+ diff = gui.Tr.SLocalize("NoTrackingThisBranch")
}
gui.renderString(g, "main", diff)
}()
diff --git a/pkg/gui/commit_message_panel.go b/pkg/gui/commit_message_panel.go
index f765ab308..26db703f0 100644
--- a/pkg/gui/commit_message_panel.go
+++ b/pkg/gui/commit_message_panel.go
@@ -1,22 +1,24 @@
package gui
-import "github.com/jesseduffield/gocui"
+import (
+ "github.com/jesseduffield/gocui"
+)
func (gui *Gui) handleCommitConfirm(g *gocui.Gui, v *gocui.View) error {
message := gui.trimmedContent(v)
if message == "" {
- return gui.createErrorPanel(g, "You cannot commit without a commit message")
+ return gui.createErrorPanel(g, gui.Tr.SLocalize("CommitWithoutMessageErr"))
}
sub, err := gui.GitCommand.Commit(g, message)
if err != nil {
// TODO need to find a way to send through this error
- if err != ErrSubProcess {
+ if err != gui.Errors.ErrSubProcess {
return gui.createErrorPanel(g, err.Error())
}
}
if sub != nil {
gui.SubProcess = sub
- return ErrSubProcess
+ return gui.Errors.ErrSubProcess
}
gui.refreshFiles(g)
v.Clear()
@@ -46,5 +48,12 @@ func (gui *Gui) handleNewlineCommitMessage(g *gocui.Gui, v *gocui.View) error {
}
func (gui *Gui) handleCommitFocused(g *gocui.Gui, v *gocui.View) error {
- return gui.renderString(g, "options", "esc: close, enter: confirm")
+ message := gui.Tr.TemplateLocalize(
+ "CloseConfirm",
+ Teml{
+ "keyBindClose": "esc",
+ "keyBindConfirm": "enter",
+ },
+ )
+ return gui.renderString(g, "options", message)
}
diff --git a/pkg/gui/commits_panel.go b/pkg/gui/commits_panel.go
index 60ae1c315..417b947a2 100644
--- a/pkg/gui/commits_panel.go
+++ b/pkg/gui/commits_panel.go
@@ -8,11 +8,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands"
)
-var (
- // ErrNoCommits : When no commits are found for the branch
- ErrNoCommits = errors.New("No commits for this branch")
-)
-
func (gui *Gui) refreshCommits(g *gocui.Gui) error {
g.Update(func(*gocui.Gui) error {
gui.State.Commits = gui.GitCommand.GetCommits()
@@ -44,7 +39,7 @@ func (gui *Gui) refreshCommits(g *gocui.Gui) error {
}
func (gui *Gui) handleResetToCommit(g *gocui.Gui, commitView *gocui.View) error {
- return gui.createConfirmationPanel(g, commitView, "Reset To Commit", "Are you sure you want to reset to this commit?", func(g *gocui.Gui, v *gocui.View) error {
+ return gui.createConfirmationPanel(g, commitView, gui.Tr.SLocalize("ResetToCommit"), gui.Tr.SLocalize("SureResetThisCommit"), func(g *gocui.Gui, v *gocui.View) error {
commit, err := gui.getSelectedCommit(g)
if err != nil {
panic(err)
@@ -65,11 +60,11 @@ func (gui *Gui) handleResetToCommit(g *gocui.Gui, commitView *gocui.View) error
func (gui *Gui) renderCommitsOptions(g *gocui.Gui) error {
return gui.renderOptionsMap(g, map[string]string{
- "s": "squash down",
- "r": "rename",
- "g": "reset to this commit",
- "f": "fixup commit",
- "← → ↑ ↓": "navigate",
+ "s": gui.Tr.SLocalize("squashDown"),
+ "r": gui.Tr.SLocalize("rename"),
+ "g": gui.Tr.SLocalize("resetToThisCommit"),
+ "f": gui.Tr.SLocalize("fixupCommit"),
+ "← → ↑ ↓": gui.Tr.SLocalize("navigate"),
})
}
@@ -79,10 +74,10 @@ func (gui *Gui) handleCommitSelect(g *gocui.Gui, v *gocui.View) error {
}
commit, err := gui.getSelectedCommit(g)
if err != nil {
- if err != ErrNoCommits {
+ if err != errors.New(gui.Tr.SLocalize("NoCommitsThisBranch")) {
return err
}
- return gui.renderString(g, "main", "No commits for this branch")
+ return gui.renderString(g, "main", gui.Tr.SLocalize("NoCommitsThisBranch"))
}
commitText := gui.GitCommand.Show(commit.Sha)
return gui.renderString(g, "main", commitText)
@@ -90,10 +85,10 @@ func (gui *Gui) handleCommitSelect(g *gocui.Gui, v *gocui.View) error {
func (gui *Gui) handleCommitSquashDown(g *gocui.Gui, v *gocui.View) error {
if gui.getItemPosition(v) != 0 {
- return gui.createErrorPanel(g, "Can only squash topmost commit")
+ return gui.createErrorPanel(g, gui.Tr.SLocalize("OnlySquashTopmostCommit"))
}
if len(gui.State.Commits) == 1 {
- return gui.createErrorPanel(g, "You have no commits to squash with")
+ return gui.createErrorPanel(g, gui.Tr.SLocalize("YouNoCommitsToSquash"))
}
commit, err := gui.getSelectedCommit(g)
if err != nil {
@@ -121,17 +116,18 @@ func (gui *Gui) anyUnStagedChanges(files []commands.File) bool {
func (gui *Gui) handleCommitFixup(g *gocui.Gui, v *gocui.View) error {
if len(gui.State.Commits) == 1 {
- return gui.createErrorPanel(g, "You have no commits to squash with")
+ return gui.createErrorPanel(g, gui.Tr.SLocalize("YouNoCommitsToSquash"))
}
if gui.anyUnStagedChanges(gui.State.Files) {
- return gui.createErrorPanel(g, "Can't fixup while there are unstaged changes")
+ return gui.createErrorPanel(g, gui.Tr.SLocalize("CantFixupWhileUnstagedChanges"))
}
branch := gui.State.Branches[0]
commit, err := gui.getSelectedCommit(g)
if err != nil {
return err
}
- gui.createConfirmationPanel(g, v, "Fixup", "Are you sure you want to fixup this commit? The commit beneath will be squashed up into this one", func(g *gocui.Gui, v *gocui.View) error {
+ message := gui.Tr.SLocalize("SureFixupThisCommit")
+ gui.createConfirmationPanel(g, v, gui.Tr.SLocalize("Fixup"), message, func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.SquashFixupCommit(branch.Name, commit.Sha); err != nil {
return gui.createErrorPanel(g, err.Error())
}
@@ -145,9 +141,9 @@ func (gui *Gui) handleCommitFixup(g *gocui.Gui, v *gocui.View) error {
func (gui *Gui) handleRenameCommit(g *gocui.Gui, v *gocui.View) error {
if gui.getItemPosition(v) != 0 {
- return gui.createErrorPanel(g, "Can only rename topmost commit")
+ return gui.createErrorPanel(g, gui.Tr.SLocalize("OnlyRenameTopCommit"))
}
- gui.createPromptPanel(g, v, "Rename Commit", func(g *gocui.Gui, v *gocui.View) error {
+ gui.createPromptPanel(g, v, gui.Tr.SLocalize("RenameCommit"), func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.RenameCommit(v.Buffer()); err != nil {
return gui.createErrorPanel(g, err.Error())
}
@@ -165,11 +161,11 @@ func (gui *Gui) getSelectedCommit(g *gocui.Gui) (commands.Commit, error) {
panic(err)
}
if len(gui.State.Commits) == 0 {
- return commands.Commit{}, ErrNoCommits
+ return commands.Commit{}, errors.New(gui.Tr.SLocalize("NoCommitsThisBranch"))
}
lineNumber := gui.getItemPosition(v)
if lineNumber > len(gui.State.Commits)-1 {
- gui.Log.Info("potential error in getSelected Commit (mismatched ui and state)", gui.State.Commits, lineNumber)
+ gui.Log.Info(gui.Tr.SLocalize("PotentialErrInGetselectedCommit"), gui.State.Commits, lineNumber)
return gui.State.Commits[len(gui.State.Commits)-1], nil
}
return gui.State.Commits[lineNumber], nil
diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go
index 5018d0a9f..9c3d2b263 100644
--- a/pkg/gui/confirmation_panel.go
+++ b/pkg/gui/confirmation_panel.go
@@ -83,7 +83,13 @@ func (gui *Gui) createConfirmationPanel(g *gocui.Gui, currentView *gocui.View, t
// delete the existing confirmation panel if it exists
if view, _ := g.View("confirmation"); view != nil {
if err := gui.closeConfirmationPrompt(g); err != nil {
- gui.Log.Error("Could not close confirmation prompt: ", err.Error())
+ errMessage := gui.Tr.TemplateLocalize(
+ "CantCloseConfirmationPrompt",
+ Teml{
+ "error": err.Error(),
+ },
+ )
+ gui.Log.Error(errMessage)
}
}
x0, y0, x1, y1 := gui.getConfirmationPanelDimensions(g, prompt)
@@ -117,7 +123,14 @@ func (gui *Gui) handleNewline(g *gocui.Gui, v *gocui.View) error {
}
func (gui *Gui) setKeyBindings(g *gocui.Gui, handleConfirm, handleClose func(*gocui.Gui, *gocui.View) error) error {
- gui.renderString(g, "options", "esc: close, enter: confirm")
+ actions := gui.Tr.TemplateLocalize(
+ "CloseConfirm",
+ Teml{
+ "keyBindClose": "esc",
+ "keyBindConfirm": "enter",
+ },
+ )
+ gui.renderString(g, "options", actions)
if err := g.SetKeybinding("confirmation", gocui.KeyEnter, gocui.ModNone, gui.wrappedConfirmationFunction(handleConfirm)); err != nil {
return err
}
@@ -135,7 +148,7 @@ func (gui *Gui) createErrorPanel(g *gocui.Gui, message string) error {
currentView := g.CurrentView()
colorFunction := color.New(color.FgRed).SprintFunc()
coloredMessage := colorFunction(strings.TrimSpace(message))
- return gui.createConfirmationPanel(g, currentView, "Error", coloredMessage, nil, nil)
+ return gui.createConfirmationPanel(g, currentView, gui.Tr.SLocalize("Error"), coloredMessage, nil, nil)
}
func (gui *Gui) resizePopupPanel(g *gocui.Gui, v *gocui.View) error {
@@ -147,7 +160,7 @@ func (gui *Gui) resizePopupPanel(g *gocui.Gui, v *gocui.View) error {
if vx0 == x0 && vy0 == y0 && vx1 == x1 && vy1 == y1 {
return nil
}
- gui.Log.Info("resizing popup panel")
+ gui.Log.Info(gui.Tr.SLocalize("resizingPopupPanel"))
_, err := g.SetView(v.Name(), x0, y0, x1, y1, 0)
return err
}
diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go
index a7e9683d2..27589bc19 100644
--- a/pkg/gui/files_panel.go
+++ b/pkg/gui/files_panel.go
@@ -7,7 +7,6 @@ import (
// "strings"
- "errors"
"os/exec"
"strings"
@@ -16,11 +15,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands"
)
-var (
- errNoFiles = errors.New("No changed files")
- errNoUsername = errors.New(`No username set. Please do: git config --global user.name "Your Name"`)
-)
-
func (gui *Gui) stagedFiles() []commands.File {
files := gui.State.Files
result := make([]commands.File, 0)
@@ -54,7 +48,7 @@ func (gui *Gui) stageSelectedFile(g *gocui.Gui) error {
func (gui *Gui) handleFilePress(g *gocui.Gui, v *gocui.View) error {
file, err := gui.getSelectedFile(g)
if err != nil {
- if err == errNoFiles {
+ if err == gui.Errors.ErrNoFiles {
return nil
}
return err
@@ -80,28 +74,28 @@ func (gui *Gui) handleFilePress(g *gocui.Gui, v *gocui.View) error {
func (gui *Gui) handleAddPatch(g *gocui.Gui, v *gocui.View) error {
file, err := gui.getSelectedFile(g)
if err != nil {
- if err == errNoFiles {
+ if err == gui.Errors.ErrNoFiles {
return nil
}
return err
}
if !file.HasUnstagedChanges {
- return gui.createErrorPanel(g, "File has no unstaged changes to add")
+ return gui.createErrorPanel(g, gui.Tr.SLocalize("FileHasNoUnstagedChanges"))
}
if !file.Tracked {
- return gui.createErrorPanel(g, "Cannot git add --patch untracked files")
+ return gui.createErrorPanel(g, gui.Tr.SLocalize("CannotGitAdd"))
}
sub, err := gui.GitCommand.AddPatch(file.Name)
if err != nil {
return err
}
gui.SubProcess = sub
- return ErrSubProcess
+ return gui.Errors.ErrSubProcess
}
func (gui *Gui) getSelectedFile(g *gocui.Gui) (commands.File, error) {
if len(gui.State.Files) == 0 {
- return commands.File{}, errNoFiles
+ return commands.File{}, gui.Errors.ErrNoFiles
}
filesView, err := g.View("files")
if err != nil {
@@ -114,18 +108,25 @@ func (gui *Gui) getSelectedFile(g *gocui.Gui) (commands.File, error) {
func (gui *Gui) handleFileRemove(g *gocui.Gui, v *gocui.View) error {
file, err := gui.getSelectedFile(g)
if err != nil {
- if err == errNoFiles {
+ if err == gui.Errors.ErrNoFiles {
return nil
}
return err
}
var deleteVerb string
if file.Tracked {
- deleteVerb = "checkout"
+ deleteVerb = gui.Tr.SLocalize("checkout")
} else {
- deleteVerb = "delete"
- }
- return gui.createConfirmationPanel(g, v, strings.Title(deleteVerb)+" file", "Are you sure you want to "+deleteVerb+" "+file.Name+" (you will lose your changes)?", func(g *gocui.Gui, v *gocui.View) error {
+ deleteVerb = gui.Tr.SLocalize("delete")
+ }
+ message := gui.Tr.TemplateLocalize(
+ "SureTo",
+ Teml{
+ "deleteVerb": deleteVerb,
+ "fileName": file.Name,
+ },
+ )
+ return gui.createConfirmationPanel(g, v, strings.Title(deleteVerb)+" file", message, func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.RemoveFile(file); err != nil {
panic(err)
}
@@ -139,7 +140,7 @@ func (gui *Gui) handleIgnoreFile(g *gocui.Gui, v *gocui.View) error {
return gui.createErrorPanel(g, err.Error())
}
if file.Tracked {
- return gui.createErrorPanel(g, "Cannot ignore tracked files")
+ return gui.createErrorPanel(g, gui.Tr.SLocalize("CantIgnoreTrackFiles"))
}
gui.GitCommand.Ignore(file.Name)
return gui.refreshFiles(g)
@@ -147,27 +148,27 @@ func (gui *Gui) handleIgnoreFile(g *gocui.Gui, v *gocui.View) error {
func (gui *Gui) renderfilesOptions(g *gocui.Gui, file *commands.File) error {
optionsMap := map[string]string{
- "← → ↑ ↓": "navigate",
- "S": "stash files",
- "c": "commit changes",
- "o": "open",
- "i": "ignore",
- "d": "delete",
- "space": "toggle staged",
- "R": "refresh",
- "t": "add patch",
- "e": "edit",
- "PgUp/PgDn": "scroll",
+ "← → ↑ ↓": gui.Tr.SLocalize("navigate"),
+ "S": gui.Tr.SLocalize("stashFiles"),
+ "c": gui.Tr.SLocalize("CommitChanges"),
+ "o": gui.Tr.SLocalize("open"),
+ "i": gui.Tr.SLocalize("ignore"),
+ "d": gui.Tr.SLocalize("delete"),
+ "space": gui.Tr.SLocalize("toggleStaged"),
+ "R": gui.Tr.SLocalize("refresh"),
+ "t": gui.Tr.SLocalize("addPatch"),
+ "e": gui.Tr.SLocalize("edit"),
+ "PgUp/PgDn": gui.Tr.SLocalize("scroll"),
}
if gui.State.HasMergeConflicts {
- optionsMap["a"] = "abort merge"
- optionsMap["m"] = "resolve merge conflicts"
+ optionsMap["a"] = gui.Tr.SLocalize("abortMerge")
+ optionsMap["m"] = gui.Tr.SLocalize("resolveMergeConflicts")
}
if file == nil {
return gui.renderOptionsMap(g, optionsMap)
}
if file.Tracked {
- optionsMap["d"] = "checkout"
+ optionsMap["d"] = gui.Tr.SLocalize("checkout")
}
return gui.renderOptionsMap(g, optionsMap)
}
@@ -175,10 +176,10 @@ func (gui *Gui) renderfilesOptions(g *gocui.Gui, file *commands.File) error {
func (gui *Gui) handleFileSelect(g *gocui.Gui, v *gocui.View) error {
file, err := gui.getSelectedFile(g)
if err != nil {
- if err != errNoFiles {
+ if err != gui.Errors.ErrNoFiles {
return err
}
- gui.renderString(g, "main", "No changed files")
+ gui.renderString(g, "main", gui.Tr.SLocalize("NoChangedFiles"))
return gui.renderfilesOptions(g, nil)
}
gui.renderfilesOptions(g, &file)
@@ -193,7 +194,7 @@ func (gui *Gui) handleFileSelect(g *gocui.Gui, v *gocui.View) error {
func (gui *Gui) handleCommitPress(g *gocui.Gui, filesView *gocui.View) error {
if len(gui.stagedFiles()) == 0 && !gui.State.HasMergeConflicts {
- return gui.createErrorPanel(g, "There are no staged files to commit")
+ return gui.createErrorPanel(g, gui.Tr.SLocalize("NoStagedFilesToCommit"))
}
commitMessageView := gui.getCommitMessageView(g)
g.Update(func(g *gocui.Gui) error {
@@ -208,7 +209,7 @@ func (gui *Gui) handleCommitPress(g *gocui.Gui, filesView *gocui.View) error {
// their editor rather than via the popup panel
func (gui *Gui) handleCommitEditorPress(g *gocui.Gui, filesView *gocui.View) error {
if len(gui.stagedFiles()) == 0 && !gui.State.HasMergeConflicts {
- return gui.createErrorPanel(g, "There are no staged files to commit")
+ return gui.createErrorPanel(g, gui.Tr.SLocalize("NoStagedFilesToCommit"))
}
gui.PrepareSubProcess(g, "git", "commit")
return nil
@@ -222,7 +223,7 @@ func (gui *Gui) PrepareSubProcess(g *gocui.Gui, commands ...string) error {
}
gui.SubProcess = sub
g.Update(func(g *gocui.Gui) error {
- return ErrSubProcess
+ return gui.Errors.ErrSubProcess
})
return nil
}
@@ -230,7 +231,7 @@ func (gui *Gui) PrepareSubProcess(g *gocui.Gui, commands ...string) error {
func (gui *Gui) genericFileOpen(g *gocui.Gui, v *gocui.View, open func(string) (*exec.Cmd, error)) error {
file, err := gui.getSelectedFile(g)
if err != nil {
- if err != errNoFiles {
+ if err != gui.Errors.ErrNoFiles {
return err
}
return nil
@@ -241,7 +242,7 @@ func (gui *Gui) genericFileOpen(g *gocui.Gui, v *gocui.View, open func(string) (
}
if sub != nil {
gui.SubProcess = sub
- return ErrSubProcess
+ return gui.Errors.ErrSubProcess
}
return nil
}
@@ -303,10 +304,10 @@ func (gui *Gui) renderFile(file commands.File, filesView *gocui.View) {
func (gui *Gui) catSelectedFile(g *gocui.Gui) (string, error) {
item, err := gui.getSelectedFile(g)
if err != nil {
- if err != errNoFiles {
+ if err != gui.Errors.ErrNoFiles {
return "", err
}
- return "", gui.renderString(g, "main", "No file to display")
+ return "", gui.renderString(g, "main", gui.Tr.SLocalize("NoFilesDisplay"))
}
cat, err := gui.GitCommand.CatFile(item.Name)
if err != nil {
@@ -333,7 +334,7 @@ func (gui *Gui) refreshFiles(g *gocui.Gui) error {
}
func (gui *Gui) pullFiles(g *gocui.Gui, v *gocui.View) error {
- gui.createMessagePanel(g, v, "", "Pulling...")
+ gui.createMessagePanel(g, v, "", gui.Tr.SLocalize("PullWait"))
go func() {
if err := gui.GitCommand.Pull(); err != nil {
gui.createErrorPanel(g, err.Error())
@@ -348,7 +349,7 @@ func (gui *Gui) pullFiles(g *gocui.Gui, v *gocui.View) error {
}
func (gui *Gui) pushFiles(g *gocui.Gui, v *gocui.View) error {
- gui.createMessagePanel(g, v, "", "Pushing...")
+ gui.createMessagePanel(g, v, "", gui.Tr.SLocalize("PushWait"))
go func() {
branchName := gui.State.Branches[0].Name
if err := gui.GitCommand.Push(branchName); err != nil {
@@ -369,13 +370,13 @@ func (gui *Gui) handleSwitchToMerge(g *gocui.Gui, v *gocui.View) error {
}
file, err := gui.getSelectedFile(g)
if err != nil {
- if err != errNoFiles {
+ if err != gui.Errors.ErrNoFiles {
return err
}
return nil
}
if !file.HasMergeConflicts {
- return gui.createErrorPanel(g, "This file has no merge conflicts")
+ return gui.createErrorPanel(g, gui.Tr.SLocalize("FileNoMergeCons"))
}
gui.switchFocus(g, v, mergeView)
return gui.refreshMergePanel(g)
@@ -385,13 +386,13 @@ func (gui *Gui) handleAbortMerge(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.AbortMerge(); err != nil {
return gui.createErrorPanel(g, err.Error())
}
- gui.createMessagePanel(g, v, "", "Merge aborted")
+ gui.createMessagePanel(g, v, "", gui.Tr.SLocalize("MergeAborted"))
gui.refreshStatus(g)
return gui.refreshFiles(g)
}
func (gui *Gui) handleResetHard(g *gocui.Gui, v *gocui.View) error {
- return gui.createConfirmationPanel(g, v, "Clear file panel", "Are you sure you want `reset --hard HEAD`? You may lose changes", func(g *gocui.Gui, v *gocui.View) error {
+ return gui.createConfirmationPanel(g, v, gui.Tr.SLocalize("ClearFilePanel"), gui.Tr.SLocalize("SureResetHardHead"), func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.ResetHard(); err != nil {
gui.createErrorPanel(g, err.Error())
}
diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go
index 3b7876ede..a5bdb9e07 100644
--- a/pkg/gui/gui.go
+++ b/pkg/gui/gui.go
@@ -19,16 +19,38 @@ import (
"github.com/golang-collections/collections/stack"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands"
+ "github.com/jesseduffield/lazygit/pkg/i18n"
)
// OverlappingEdges determines if panel edges overlap
var OverlappingEdges = false
-// ErrSubProcess tells us we're switching to a subprocess so we need to
-// close the Gui until it is finished
-var (
- ErrSubProcess = errors.New("running subprocess")
-)
+// SentinelErrors are the errors that have special meaning and need to be checked
+// by calling functions. The less of these, the better
+type SentinelErrors struct {
+ ErrSubProcess error
+ ErrNoFiles error
+}
+
+// GenerateSentinelErrors makes the sentinel errors for the gui. We're defining it here
+// because we can't do package-scoped errors with localization, and also because
+// it seems like package-scoped variables are bad in general
+// https://dave.cheney.net/2017/06/11/go-without-package-scoped-variables
+// In the future it would be good to implement some of the recommendations of
+// that article. For now, if we don't need an error to be a sentinel, we will just
+// define it inline. This has implications for error messages that pop up everywhere
+// in that we'll be duplicating the default values. We may need to look at
+// having a default localisation bundle defined, and just using keys-only when
+// localising things in the code.
+func (gui *Gui) GenerateSentinelErrors() {
+ gui.Errors = SentinelErrors{
+ ErrSubProcess: errors.New(gui.Tr.SLocalize("RunningSubprocess")),
+ ErrNoFiles: errors.New(gui.Tr.SLocalize("NoChangedFiles")),
+ }
+}
+
+// Teml is short for template used to make the required map[string]interface{} shorter when using gui.Tr.SLocalize and gui.Tr.TemplateLocalize
+type Teml i18n.Teml
// Gui wraps the gocui Gui object which handles rendering and events
type Gui struct {
@@ -39,6 +61,8 @@ type Gui struct {
Version string
SubProcess *exec.Cmd
State guiState
+ Tr *i18n.Localizer
+ Errors SentinelErrors
}
type guiState struct {
@@ -57,7 +81,7 @@ type guiState struct {
}
// NewGui builds a new gui handler
-func NewGui(log *logrus.Logger, gitCommand *commands.GitCommand, oSCommand *commands.OSCommand, version string) (*Gui, error) {
+func NewGui(log *logrus.Logger, gitCommand *commands.GitCommand, oSCommand *commands.OSCommand, tr *i18n.Localizer, version string) (*Gui, error) {
initialState := guiState{
Files: make([]commands.File, 0),
PreviousView: "files",
@@ -71,13 +95,18 @@ func NewGui(log *logrus.Logger, gitCommand *commands.GitCommand, oSCommand *comm
Version: version,
}
- return &Gui{
+ gui := &Gui{
Log: log,
GitCommand: gitCommand,
OSCommand: oSCommand,
Version: version,
State: initialState,
- }, nil
+ Tr: tr,
+ }
+
+ gui.GenerateSentinelErrors()
+
+ return gui, nil
}
func (gui *Gui) scrollUpMain(g *gocui.Gui, v *gocui.View) error {
@@ -133,7 +162,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
if err != gocui.ErrUnknownView {
return err
}
- v.Title = "Not enough space to render panels"
+ v.Title = gui.Tr.SLocalize("NotEnoughSpace")
v.Wrap = true
}
return nil
@@ -152,7 +181,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
if err != gocui.ErrUnknownView {
return err
}
- v.Title = "Diff"
+ v.Title = gui.Tr.SLocalize("DiffTitle")
v.Wrap = true
v.FgColor = gocui.ColorWhite
}
@@ -161,7 +190,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
if err != gocui.ErrUnknownView {
return err
}
- v.Title = "Status"
+ v.Title = gui.Tr.SLocalize("StatusTitle")
v.FgColor = gocui.ColorWhite
}
@@ -171,7 +200,7 @@ func (gui *Gui) layout(g *gocui.Gui)