diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index d4117364..12792cf6 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -19,14 +19,25 @@ jobs:
os: macos-latest
runtime: osx-arm64
- name : Linux
- os: ubuntu-20.04
+ os: ubuntu-latest
runtime: linux-x64
+ container: ubuntu:20.04
- name : Linux (arm64)
- os: ubuntu-20.04
+ os: ubuntu-latest
runtime: linux-arm64
+ container: ubuntu:20.04
name: Build ${{ matrix.name }}
runs-on: ${{ matrix.os }}
+ container: ${{ matrix.container || '' }}
steps:
+ - name: Install common CLI tools
+ if: ${{ startsWith(matrix.runtime, 'linux-') }}
+ run: |
+ export DEBIAN_FRONTEND=noninteractive
+ ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime
+ apt-get update
+ apt-get install -y sudo
+ sudo apt-get install -y curl wget git unzip zip libicu66 tzdata clang
- name: Checkout sources
uses: actions/checkout@v4
- name: Setup .NET
@@ -47,7 +58,7 @@ jobs:
if: ${{ matrix.runtime == 'linux-arm64' }}
run: |
sudo apt-get update
- sudo apt-get install clang llvm gcc-aarch64-linux-gnu zlib1g-dev:arm64
+ sudo apt-get install -y llvm gcc-aarch64-linux-gnu
- name: Build
run: dotnet build -c Release
- name: Publish
diff --git a/.github/workflows/localization-check.yml b/.github/workflows/localization-check.yml
index cc5201ab..8dcd61c8 100644
--- a/.github/workflows/localization-check.yml
+++ b/.github/workflows/localization-check.yml
@@ -4,7 +4,6 @@ on:
branches: [ develop ]
paths:
- 'src/Resources/Locales/**'
- - 'README.md'
workflow_dispatch:
workflow_call:
@@ -32,8 +31,8 @@ jobs:
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
if [ -n "$(git status --porcelain)" ]; then
- git add README.md TRANSLATION.md
- git commit -m 'doc: Update translation status and missing keys'
+ git add TRANSLATION.md src/Resources/Locales/*.axaml
+ git commit -m 'doc: Update translation status and sort locale files'
git push
else
echo "No changes to commit"
diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml
index e973c1ab..2dfc97fd 100644
--- a/.github/workflows/package.yml
+++ b/.github/workflows/package.yml
@@ -7,12 +7,12 @@ on:
required: true
type: string
jobs:
- windows-portable:
- name: Package portable Windows app
- runs-on: ubuntu-latest
+ windows:
+ name: Package Windows
+ runs-on: windows-2019
strategy:
matrix:
- runtime: [win-x64, win-arm64]
+ runtime: [ win-x64, win-arm64 ]
steps:
- name: Checkout sources
uses: actions/checkout@v4
@@ -22,10 +22,11 @@ jobs:
name: sourcegit.${{ matrix.runtime }}
path: build/SourceGit
- name: Package
+ shell: bash
env:
VERSION: ${{ inputs.version }}
RUNTIME: ${{ matrix.runtime }}
- run: ./build/scripts/package.windows-portable.sh
+ run: ./build/scripts/package.windows.sh
- name: Upload package artifact
uses: actions/upload-artifact@v4
with:
@@ -36,7 +37,7 @@ jobs:
with:
name: sourcegit.${{ matrix.runtime }}
osx-app:
- name: Package OSX app
+ name: Package macOS
runs-on: macos-latest
strategy:
matrix:
@@ -69,6 +70,7 @@ jobs:
linux:
name: Package Linux
runs-on: ubuntu-latest
+ container: ubuntu:20.04
strategy:
matrix:
runtime: [linux-x64, linux-arm64]
@@ -77,9 +79,10 @@ jobs:
uses: actions/checkout@v4
- name: Download package dependencies
run: |
- sudo add-apt-repository universe
- sudo apt-get update
- sudo apt-get install desktop-file-utils rpm libfuse2
+ export DEBIAN_FRONTEND=noninteractive
+ ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime
+ apt-get update
+ apt-get install -y curl wget git dpkg-dev fakeroot tzdata zip unzip desktop-file-utils rpm libfuse2 file build-essential binutils
- name: Download build
uses: actions/download-artifact@v4
with:
@@ -89,6 +92,7 @@ jobs:
env:
VERSION: ${{ inputs.version }}
RUNTIME: ${{ matrix.runtime }}
+ APPIMAGE_EXTRACT_AND_RUN: 1
run: |
mkdir build/SourceGit
tar -xf "build/sourcegit.${{ matrix.runtime }}.tar" -C build/SourceGit
diff --git a/.github/workflows/publish-packages.yml b/.github/workflows/publish-packages.yml
deleted file mode 100644
index 9e465fe7..00000000
--- a/.github/workflows/publish-packages.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-name: Publish to Buildkite
-on:
- workflow_call:
- secrets:
- BUILDKITE_TOKEN:
- required: true
-jobs:
- publish:
- name: Publish to Buildkite
- runs-on: ubuntu-latest
- strategy:
- matrix:
- runtime: [linux-x64, linux-arm64]
- steps:
- - name: Download package artifacts
- uses: actions/download-artifact@v4
- with:
- name: package.${{ matrix.runtime }}
- path: packages
-
- - name: Publish DEB package
- env:
- BUILDKITE_TOKEN: ${{ secrets.BUILDKITE_TOKEN }}
- run: |
- FILE=$(echo packages/*.deb)
- curl -X POST https://api.buildkite.com/v2/packages/organizations/sourcegit/registries/sourcegit-deb/packages \
- -H "Authorization: Bearer $BUILDKITE_TOKEN" \
- -F "file=@$FILE" \
- --fail
-
- - name: Publish RPM package
- env:
- BUILDKITE_TOKEN: ${{ secrets.BUILDKITE_TOKEN }}
- run: |
- FILE=$(echo packages/*.rpm)
- curl -X POST https://api.buildkite.com/v2/packages/organizations/sourcegit/registries/sourcegit-rpm/packages \
- -H "Authorization: Bearer $BUILDKITE_TOKEN" \
- -F "file=@$FILE" \
- --fail
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 223fe75f..e61e608b 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -24,12 +24,6 @@ jobs:
uses: ./.github/workflows/package.yml
with:
version: ${{ needs.version.outputs.version }}
- publish-packages:
- needs: [package, version]
- name: Publish Packages
- uses: ./.github/workflows/publish-packages.yml
- secrets:
- BUILDKITE_TOKEN: ${{ secrets.BUILDKITE_TOKEN }}
release:
needs: [package, version]
name: Release
@@ -44,7 +38,7 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ github.ref_name }}
VERSION: ${{ needs.version.outputs.version }}
- run: gh release create "$TAG" -t "Release $VERSION" --notes-from-tag
+ run: gh release create "$TAG" -t "$VERSION" --notes-from-tag
- name: Download artifacts
uses: actions/download-artifact@v4
with:
diff --git a/.gitignore b/.gitignore
index 0c66b11e..e686a534 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,3 +37,5 @@ build/*.deb
build/*.rpm
build/*.AppImage
SourceGit.app/
+build.command
+src/Properties/launchSettings.json
diff --git a/LICENSE b/LICENSE
index dceab2d8..442ce085 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2024 sourcegit
+Copyright (c) 2025 sourcegit
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
@@ -17,4 +17,4 @@ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
index 6916edbc..f9ba3072 100644
--- a/README.md
+++ b/README.md
@@ -11,16 +11,16 @@
* Supports Windows/macOS/Linux
* Opensource/Free
* Fast
-* Deutsch/English/Español/Français/Italiano/Português/Русский/简体中文/繁體中文
+* Deutsch/English/Español/Français/Italiano/Português/Русский/Українська/简体中文/繁體中文/日本語/தமிழ் (Tamil)
* Built-in light/dark themes
* Customize theme
* Visual commit graph
* Supports SSH access with each remote
* GIT commands with GUI
* Clone/Fetch/Pull/Push...
- * Merge/Rebase/Reset/Revert/Amend/Cherry-pick...
- * Amend/Reword
- * Interactive rebase (Basic)
+ * Merge/Rebase/Reset/Revert/Cherry-pick...
+ * Amend/Reword/Squash
+ * Interactive rebase
* Branches
* Remotes
* Tags
@@ -35,11 +35,14 @@
* Revision Diffs
* Branch Diff
* Image Diff - Side-By-Side/Swipe/Blend
+* Git command logs
* Search commits
* GitFlow
* Git LFS
+* Bisect
* Issue Link
* Workspace
+* Custom Action
* Using AI to generate commit message (C# port of [anjerodev/commitollama](https://github.com/anjerodev/commitollama))
> [!WARNING]
@@ -47,24 +50,25 @@
## Translation Status
-[](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md)
+You can find the current translation status in [TRANSLATION.md](https://github.com/sourcegit-scm/sourcegit/blob/develop/TRANSLATION.md)
## How to Use
-**To use this tool, you need to install Git(>=2.23.0) first.**
+**To use this tool, you need to install Git(>=2.25.1) first.**
-You can download the latest stable from [Releases](https://github.com/sourcegit-scm/sourcegit/releases/latest) or download workflow artifacts from [Github Actions](https://github.com/sourcegit-scm/sourcegit/actions) to try this app based on latest commits.
+You can download the latest stable from [Releases](https://github.com/sourcegit-scm/sourcegit/releases/latest) or download workflow artifacts from [GitHub Actions](https://github.com/sourcegit-scm/sourcegit/actions) to try this app based on latest commits.
This software creates a folder `$"{System.Environment.SpecialFolder.ApplicationData}/SourceGit"`, which is platform-dependent, to store user settings, downloaded avatars and crash logs.
| OS | PATH |
|---------|-----------------------------------------------------|
-| Windows | `C:\Users\USER_NAME\AppData\Roaming\SourceGit` |
+| Windows | `%APPDATA%\SourceGit` |
| Linux | `${HOME}/.config/SourceGit` or `${HOME}/.sourcegit` |
| macOS | `${HOME}/Library/Application Support/SourceGit` |
> [!TIP]
-> You can open the app data dir from the main menu.
+> * You can open this data storage directory from the main menu `Open Data Storage Directory`.
+> * You can create a `data` folder next to the `SourceGit` executable to force this app to store data (user settings, downloaded avatars and crash logs) into it (Portable-Mode). Only works on Windows.
For **Windows** users:
@@ -75,12 +79,12 @@ For **Windows** users:
```
> [!NOTE]
> `winget` will install this software as a commandline tool. You need run `SourceGit` from console or `Win+R` at the first time. Then you can add it to the taskbar.
-* You can install the latest stable by `scoope` with follow commands:
+* You can install the latest stable by `scoop` with follow commands:
```shell
scoop bucket add extras
scoop install sourcegit
```
-* Portable versions can be found in [Releases](https://github.com/sourcegit-scm/sourcegit/releases/latest)
+* Pre-built binaries can be found in [Releases](https://github.com/sourcegit-scm/sourcegit/releases/latest)
For **macOS** users:
@@ -89,7 +93,7 @@ For **macOS** users:
brew tap ybeapps/homebrew-sourcegit
brew install --cask --no-quarantine sourcegit
```
-* If you want to install `SourceGit.app` from Github Release manually, you need run following command to make sure it works:
+* If you want to install `SourceGit.app` from GitHub Release manually, you need run following command to make sure it works:
```shell
sudo xattr -cr /Applications/SourceGit.app
```
@@ -98,49 +102,45 @@ For **macOS** users:
For **Linux** users:
-* For Debian/Ubuntu based distributions, you can add the `sourcegit` repository by following:
- You may need to install curl and/or gpg first, if you're on a very minimal host:
+* Thanks [@aikawayataro](https://github.com/aikawayataro) for providing `rpm` and `deb` repositories, hosted on [Codeberg](https://codeberg.org/yataro/-/packages).
+
+ `deb` how to:
```shell
- apt update && apt install curl gpg -y
+ curl https://codeberg.org/api/packages/yataro/debian/repository.key | sudo tee /etc/apt/keyrings/sourcegit.asc
+ echo "deb [signed-by=/etc/apt/keyrings/sourcegit.asc, arch=amd64,arm64] https://codeberg.org/api/packages/yataro/debian generic main" | sudo tee /etc/apt/sources.list.d/sourcegit.list
+ sudo apt update
+ sudo apt install sourcegit
```
- Install the registry signing key:
+
+ `rpm` how to:
```shell
- curl -fsSL "https://packages.buildkite.com/sourcegit/sourcegit-deb/gpgkey" | gpg --dearmor -o /etc/apt/keyrings/sourcegit_sourcegit-deb-archive-keyring.gpg
+ curl https://codeberg.org/api/packages/yataro/rpm.repo | sed -e 's/gpgcheck=1/gpgcheck=0/' > sourcegit.repo
+
+ # Fedora 41 and newer
+ sudo dnf config-manager addrepo --from-repofile=./sourcegit.repo
+ # Fedora 40 and earlier
+ sudo dnf config-manager --add-repo ./sourcegit.repo
+
+ sudo dnf install sourcegit
```
- Configure the source:
- ```shell
- echo -e "deb [signed-by=/etc/apt/keyrings/sourcegit_sourcegit-deb-archive-keyring.gpg] https://packages.buildkite.com/sourcegit/sourcegit-deb/any/ any main\ndeb-src [signed-by=/etc/apt/keyrings/sourcegit_sourcegit-deb-archive-keyring.gpg] https://packages.buildkite.com/sourcegit/sourcegit-deb/any/ any main" > /etc/apt/sources.list.d/buildkite-sourcegit-sourcegit-deb.list
- ```
- Update your local repository and install the package:
- ```shell
- apt update && apt install sourcegit
- ```
-* For RHEL/Fedora based distributions, you can add the `sourcegit` repository by following:
- Configure the source:
- ```shell
- sudo sh -c 'echo -e "[sourcegit-rpm]\nname=sourcegit-rpm\nbaseurl=https://packages.buildkite.com/sourcegit/sourcegit-rpm/rpm_any/rpm_any/\$basearch\nenabled=1\nrepo_gpgcheck=1\ngpgcheck=0\ngpgkey=https://packages.buildkite.com/sourcegit/sourcegit-rpm/gpgkey\npriority=1"' > /etc/yum.repos.d/sourcegit-rpm.repo
- ```
- Install the package with this command:
- ```shell
- sudo dnf install -y sourcegit
- ```
-* `Appimage` files can be found on [AppimageHub](https://appimage.github.io/SourceGit/)
-* `xdg-open` must be installed to support open native file manager.
-* Make sure [git-credential-manager](https://github.com/git-ecosystem/git-credential-manager/releases) is installed on your linux.
+
+ If your distribution isn't using `dnf`, please refer to the documentation of your distribution on how to add an `rpm` repository.
+* `AppImage` files can be found on [AppImage hub](https://appimage.github.io/SourceGit/), `xdg-open` (`xdg-utils`) must be installed to support open native file manager.
+* Make sure [git-credential-manager](https://github.com/git-ecosystem/git-credential-manager/releases) is installed on your Linux.
* Maybe you need to set environment variable `AVALONIA_SCREEN_SCALE_FACTORS`. See https://github.com/AvaloniaUI/Avalonia/wiki/Configuring-X11-per-monitor-DPI.
-* If you can NOT type accented characters, such as `ê`, `ó`, try to set the environment variable `AVALONIA_IM_MODULE` to `none`.
+* If you can NOT type accented characters, such as `ê`, `ó`, try to set the environment variable `AVALONIA_IM_MODULE` to `none`.
## OpenAI
-This software supports using OpenAI or other AI service that has an OpenAI comaptible HTTP API to generate commit message. You need configurate the service in `Preference` window.
+This software supports using OpenAI or other AI service that has an OpenAI compatible HTTP API to generate commit message. You need configurate the service in `Preference` window.
For `OpenAI`:
-* `Server` must be `https://api.openai.com/v1/chat/completions`
+* `Server` must be `https://api.openai.com/v1`
For other AI service:
-* The `Server` should fill in a URL equivalent to OpenAI's `https://api.openai.com/v1/chat/completions`. For example, when using `Ollama`, it should be `http://localhost:11434/v1/chat/completions` instead of `http://localhost:11434/api/generate`
+* The `Server` should fill in a URL equivalent to OpenAI's `https://api.openai.com/v1`. For example, when using `Ollama`, it should be `http://localhost:11434/v1` instead of `http://localhost:11434/api/generate`
* The `API Key` is optional that depends on the service
## External Tools
@@ -159,7 +159,7 @@ This app supports open repository in external tools listed in the table below.
> [!NOTE]
> This app will try to find those tools based on some pre-defined or expected locations automatically. If you are using one portable version of these tools, it will not be detected by this app.
-> To solve this problem you can add a file named `external_editors.json` in app data dir and provide the path directly. For example:
+> To solve this problem you can add a file named `external_editors.json` in app data storage directory and provide the path directly. For example:
```json
{
"tools": {
@@ -189,6 +189,19 @@ This app supports open repository in external tools listed in the table below.
Everyone is welcome to submit a PR. Please make sure your PR is based on the latest `develop` branch and the target branch of PR is `develop`.
+In short, here are the commands to get started once [.NET tools are installed](https://dotnet.microsoft.com/en-us/download):
+
+```sh
+dotnet nuget add source https://api.nuget.org/v3/index.json -n nuget.org
+dotnet restore
+dotnet build
+dotnet run --project src/SourceGit.csproj
+```
+
Thanks to all the people who contribute.
[](https://github.com/sourcegit-scm/sourcegit/graphs/contributors)
+
+## Third-Party Components
+
+For detailed license information, see [THIRD-PARTY-LICENSES.md](THIRD-PARTY-LICENSES.md).
diff --git a/SourceGit.sln b/SourceGit.sln
index 3eeb8a54..624322f8 100644
--- a/SourceGit.sln
+++ b/SourceGit.sln
@@ -18,7 +18,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{
.github\workflows\package.yml = .github\workflows\package.yml
.github\workflows\release.yml = .github\workflows\release.yml
.github\workflows\localization-check.yml = .github\workflows\localization-check.yml
- .github\workflows\publish-packages.yml = .github\workflows\publish-packages.yml
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{49A7C2D6-558C-4FAA-8F5D-EEE81497AED7}"
@@ -61,6 +60,8 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DEBIAN", "DEBIAN", "{F101849D-BDB7-40D4-A516-751150C3CCFC}"
ProjectSection(SolutionItems) = preProject
build\resources\deb\DEBIAN\control = build\resources\deb\DEBIAN\control
+ build\resources\deb\DEBIAN\preinst = build\resources\deb\DEBIAN\preinst
+ build\resources\deb\DEBIAN\prerm = build\resources\deb\DEBIAN\prerm
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "rpm", "rpm", "{9BA0B044-0CC9-46F8-B551-204F149BF45D}"
@@ -81,7 +82,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{C54D
build\scripts\localization-check.js = build\scripts\localization-check.js
build\scripts\package.linux.sh = build\scripts\package.linux.sh
build\scripts\package.osx-app.sh = build\scripts\package.osx-app.sh
- build\scripts\package.windows-portable.sh = build\scripts\package.windows-portable.sh
+ build\scripts\package.windows.sh = build\scripts\package.windows.sh
EndProjectSection
EndProject
Global
diff --git a/THIRD-PARTY-LICENSES.md b/THIRD-PARTY-LICENSES.md
new file mode 100644
index 00000000..2338263c
--- /dev/null
+++ b/THIRD-PARTY-LICENSES.md
@@ -0,0 +1,86 @@
+# Third-Party Licenses
+
+This project incorporates components from the following third parties:
+
+## Packages
+
+### AvaloniaUI
+
+- **Source**: https://github.com/AvaloniaUI/Avalonia
+- **Version**: 11.2.5
+- **License**: MIT License
+- **License Link**: https://github.com/AvaloniaUI/Avalonia/blob/master/licence.md
+
+### AvaloniaEdit
+
+- **Source**: https://github.com/AvaloniaUI/AvaloniaEdit
+- **Version**: 11.2.0
+- **License**: MIT License
+- **License Link**: https://github.com/AvaloniaUI/AvaloniaEdit/blob/master/LICENSE
+
+### LiveChartsCore.SkiaSharpView.Avalonia
+
+- **Source**: https://github.com/beto-rodriguez/LiveCharts2
+- **Version**: 2.0.0-rc5.4
+- **License**: MIT License
+- **License Link**: https://github.com/beto-rodriguez/LiveCharts2/blob/master/LICENSE
+
+### TextMateSharp
+
+- **Source**: https://github.com/danipen/TextMateSharp
+- **Version**: 1.0.66
+- **License**: MIT License
+- **License Link**: https://github.com/danipen/TextMateSharp/blob/master/LICENSE.md
+
+### OpenAI .NET SDK
+
+- **Source**: https://github.com/openai/openai-dotnet
+- **Version**: 2.2.0-beta2
+- **License**: MIT License
+- **License Link**: https://github.com/openai/openai-dotnet/blob/main/LICENSE
+
+### Azure.AI.OpenAI
+
+- **Source**: https://github.com/Azure/azure-sdk-for-net
+- **Version**: 2.2.0-beta2
+- **License**: MIT License
+- **License Link**: https://github.com/Azure/azure-sdk-for-net/blob/main/LICENSE.txt
+
+## Fonts
+
+### JetBrainsMono
+
+- **Source**: https://github.com/JetBrains/JetBrainsMono
+- **Commit**: v2.304
+- **License**: SIL Open Font License, Version 1.1
+- **License Link**: https://github.com/JetBrains/JetBrainsMono/blob/v2.304/OFL.txt
+
+## Grammar Files
+
+### haxe-TmLanguage
+
+- **Source**: https://github.com/vshaxe/haxe-TmLanguage
+- **Commit**: ddad8b4c6d0781ac20be0481174ec1be772c5da5
+- **License**: MIT License
+- **License Link**: https://github.com/vshaxe/haxe-TmLanguage/blob/ddad8b4c6d0781ac20be0481174ec1be772c5da5/LICENSE.md
+
+### coc-toml
+
+- **Source**: https://github.com/kkiyama117/coc-toml
+- **Commit**: aac3e0c65955c03314b2733041b19f903b7cc447
+- **License**: MIT License
+- **License Link**: https://github.com/kkiyama117/coc-toml/blob/aac3e0c65955c03314b2733041b19f903b7cc447/LICENSE
+
+### eclipse-buildship
+
+- **Source**: https://github.com/eclipse/buildship
+- **Commit**: 6bb773e7692f913dec27105129ebe388de34e68b
+- **License**: Eclipse Public License 1.0
+- **License Link**: https://github.com/eclipse-buildship/buildship/blob/6bb773e7692f913dec27105129ebe388de34e68b/README.md
+
+### vscode-jsp-lang
+
+- **Source**: https://github.com/samuel-weinhardt/vscode-jsp-lang
+- **Commit**: 0e89ecdb13650dbbe5a1e85b47b2e1530bf2f355
+- **License**: MIT License
+- **License Link**: https://github.com/samuel-weinhardt/vscode-jsp-lang/blob/0e89ecdb13650dbbe5a1e85b47b2e1530bf2f355/LICENSE
diff --git a/TRANSLATION.md b/TRANSLATION.md
index 6e743f14..ba51b82c 100644
--- a/TRANSLATION.md
+++ b/TRANSLATION.md
@@ -1,213 +1,496 @@
-### de_DE.axaml: 97.50%
+# Translation Status
+This document shows the translation status of each locale file in the repository.
+
+## Details
+
+### 
+
+### 
-Missing Keys
+Missing keys in de_DE.axaml
-- Text.BranchCM.MergeMultiBranches
-- Text.CommitCM.Merge
-- Text.CommitCM.MergeMultiple
-- Text.CommitDetail.Files.Search
-- Text.Diff.UseBlockNavigation
-- Text.FileCM.ResolveUsing
-- Text.Hotkeys.Global.Clone
-- Text.InProgress.CherryPick.Head
-- Text.InProgress.Merge.Operating
-- Text.InProgress.Rebase.StoppedAt
-- Text.InProgress.Revert.Head
-- Text.Merge.Source
-- Text.MergeMultiple
-- Text.MergeMultiple.CommitChanges
-- Text.MergeMultiple.Strategy
-- Text.MergeMultiple.Targets
-- Text.Repository.Skip
-- Text.WorkingCopy.CommitToEdit
+- Text.Avatar.Load
+- Text.BranchCM.ResetToSelectedCommit
+- Text.CommitDetail.Changes.Count
+- Text.CreateBranch.OverwriteExisting
+- Text.DeinitSubmodule
+- Text.DeinitSubmodule.Force
+- Text.DeinitSubmodule.Path
+- Text.Diff.Submodule.Deleted
+- Text.GitFlow.FinishWithPush
+- Text.GitFlow.FinishWithSquash
+- Text.Hotkeys.Global.SwitchWorkspace
+- Text.Hotkeys.Global.SwitchTab
+- Text.Hotkeys.TextEditor.OpenExternalMergeTool
+- Text.Launcher.Workspaces
+- Text.Launcher.Pages
+- Text.Pull.RecurseSubmodules
+- Text.Repository.ClearStashes
+- Text.Repository.ShowSubmodulesAsTree
+- Text.ResetWithoutCheckout
+- Text.ResetWithoutCheckout.MoveTo
+- Text.ResetWithoutCheckout.Target
+- Text.Submodule.Deinit
+- Text.Submodule.Status
+- Text.Submodule.Status.Modified
+- Text.Submodule.Status.NotInited
+- Text.Submodule.Status.RevisionChanged
+- Text.Submodule.Status.Unmerged
+- Text.Submodule.URL
+- Text.WorkingCopy.ResetAuthor
-### es_ES.axaml: 97.78%
-
+### 
-Missing Keys
+Missing keys in es_ES.axaml
-- Text.BranchCM.MergeMultiBranches
-- Text.CommitCM.Merge
-- Text.CommitCM.MergeMultiple
-- Text.Diff.UseBlockNavigation
-- Text.FileCM.ResolveUsing
-- Text.Hotkeys.Global.Clone
-- Text.InProgress.CherryPick.Head
-- Text.InProgress.Merge.Operating
-- Text.InProgress.Rebase.StoppedAt
-- Text.InProgress.Revert.Head
-- Text.Merge.Source
-- Text.MergeMultiple
-- Text.MergeMultiple.CommitChanges
-- Text.MergeMultiple.Strategy
-- Text.MergeMultiple.Targets
-- Text.Repository.Skip
+- Text.Avatar.Load
-### fr_FR.axaml: 95.00%
-
+### 
-Missing Keys
+Missing keys in fr_FR.axaml
-- Text.BranchCM.MergeMultiBranches
-- Text.CherryPick.AppendSourceToMessage
-- Text.CherryPick.Mainline.Tips
-- Text.CommitCM.CherryPickMultiple
-- Text.CommitCM.Merge
-- Text.CommitCM.MergeMultiple
-- Text.CommitDetail.Files.Search
-- Text.Diff.UseBlockNavigation
-- Text.Fetch.Force
-- Text.FileCM.ResolveUsing
-- Text.Hotkeys.Global.Clone
-- Text.InProgress.CherryPick.Head
-- Text.InProgress.Merge.Operating
-- Text.InProgress.Rebase.StoppedAt
-- Text.InProgress.Revert.Head
-- Text.Merge.Source
-- Text.MergeMultiple
-- Text.MergeMultiple.CommitChanges
-- Text.MergeMultiple.Strategy
-- Text.MergeMultiple.Targets
-- Text.Preference.Appearance.FontSize
-- Text.Preference.Appearance.FontSize.Default
-- Text.Preference.Appearance.FontSize.Editor
-- Text.Preference.General.ShowChildren
-- Text.Repository.CustomActions
+- Text.Avatar.Load
+- Text.Bisect
+- Text.Bisect.Abort
+- Text.Bisect.Bad
+- Text.Bisect.Detecting
+- Text.Bisect.Good
+- Text.Bisect.Skip
+- Text.Bisect.WaitingForRange
+- Text.BranchCM.ResetToSelectedCommit
+- Text.Checkout.RecurseSubmodules
+- Text.CommitCM.CopyAuthor
+- Text.CommitCM.CopyCommitter
+- Text.CommitCM.CopySubject
+- Text.CommitDetail.Changes.Count
+- Text.CommitMessageTextBox.SubjectCount
+- Text.Configure.Git.PreferredMergeMode
+- Text.ConfirmEmptyCommit.Continue
+- Text.ConfirmEmptyCommit.NoLocalChanges
+- Text.ConfirmEmptyCommit.StageAllThenCommit
+- Text.ConfirmEmptyCommit.WithLocalChanges
+- Text.CreateBranch.OverwriteExisting
+- Text.DeinitSubmodule
+- Text.DeinitSubmodule.Force
+- Text.DeinitSubmodule.Path
+- Text.Diff.Submodule.Deleted
+- Text.GitFlow.FinishWithPush
+- Text.GitFlow.FinishWithSquash
+- Text.Hotkeys.Global.SwitchWorkspace
+- Text.Hotkeys.Global.SwitchTab
+- Text.Hotkeys.TextEditor.OpenExternalMergeTool
+- Text.Launcher.Workspaces
+- Text.Launcher.Pages
+- Text.Preferences.Git.IgnoreCRAtEOLInDiff
+- Text.Pull.RecurseSubmodules
+- Text.Repository.BranchSort
+- Text.Repository.BranchSort.ByCommitterDate
+- Text.Repository.BranchSort.ByName
+- Text.Repository.ClearStashes
+- Text.Repository.Search.ByContent
+- Text.Repository.ShowSubmodulesAsTree
+- Text.Repository.ViewLogs
+- Text.Repository.Visit
+- Text.ResetWithoutCheckout
+- Text.ResetWithoutCheckout.MoveTo
+- Text.ResetWithoutCheckout.Target
+- Text.Submodule.Deinit
+- Text.Submodule.Status
+- Text.Submodule.Status.Modified
+- Text.Submodule.Status.NotInited
+- Text.Submodule.Status.RevisionChanged
+- Text.Submodule.Status.Unmerged
+- Text.Submodule.URL
+- Text.ViewLogs
+- Text.ViewLogs.Clear
+- Text.ViewLogs.CopyLog
+- Text.ViewLogs.Delete
+- Text.WorkingCopy.ConfirmCommitWithFilter
+- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
+- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
+- Text.WorkingCopy.Conflicts.UseMine
+- Text.WorkingCopy.Conflicts.UseTheirs
+- Text.WorkingCopy.ResetAuthor
+
+
+
+### 
+
+
+Missing keys in it_IT.axaml
+
+- Text.Avatar.Load
+- Text.BranchCM.ResetToSelectedCommit
+- Text.CommitDetail.Changes.Count
+- Text.CreateBranch.OverwriteExisting
+- Text.DeinitSubmodule
+- Text.DeinitSubmodule.Force
+- Text.DeinitSubmodule.Path
+- Text.Diff.Submodule.Deleted
+- Text.Hotkeys.Global.SwitchWorkspace
+- Text.Hotkeys.Global.SwitchTab
+- Text.Launcher.Workspaces
+- Text.Launcher.Pages
+- Text.Pull.RecurseSubmodules
+- Text.Repository.ClearStashes
+- Text.ResetWithoutCheckout
+- Text.ResetWithoutCheckout.MoveTo
+- Text.ResetWithoutCheckout.Target
+- Text.Submodule.Deinit
+- Text.WorkingCopy.ResetAuthor
+
+
+
+### 
+
+
+Missing keys in ja_JP.axaml
+
+- Text.Avatar.Load
+- Text.Bisect
+- Text.Bisect.Abort
+- Text.Bisect.Bad
+- Text.Bisect.Detecting
+- Text.Bisect.Good
+- Text.Bisect.Skip
+- Text.Bisect.WaitingForRange
+- Text.BranchCM.CompareWithCurrent
+- Text.BranchCM.ResetToSelectedCommit
+- Text.Checkout.RecurseSubmodules
+- Text.CommitCM.CopyAuthor
+- Text.CommitCM.CopyCommitter
+- Text.CommitCM.CopySubject
+- Text.CommitDetail.Changes.Count
+- Text.CommitMessageTextBox.SubjectCount
+- Text.Configure.Git.PreferredMergeMode
+- Text.ConfirmEmptyCommit.Continue
+- Text.ConfirmEmptyCommit.NoLocalChanges
+- Text.ConfirmEmptyCommit.StageAllThenCommit
+- Text.ConfirmEmptyCommit.WithLocalChanges
+- Text.CreateBranch.OverwriteExisting
+- Text.DeinitSubmodule
+- Text.DeinitSubmodule.Force
+- Text.DeinitSubmodule.Path
+- Text.Diff.Submodule.Deleted
+- Text.GitFlow.FinishWithPush
+- Text.GitFlow.FinishWithSquash
+- Text.Hotkeys.Global.SwitchWorkspace
+- Text.Hotkeys.Global.SwitchTab
+- Text.Hotkeys.TextEditor.OpenExternalMergeTool
+- Text.Launcher.Workspaces
+- Text.Launcher.Pages
+- Text.Preferences.Git.IgnoreCRAtEOLInDiff
+- Text.Pull.RecurseSubmodules
+- Text.Repository.BranchSort
+- Text.Repository.BranchSort.ByCommitterDate
+- Text.Repository.BranchSort.ByName
+- Text.Repository.ClearStashes
- Text.Repository.FilterCommits
-- Text.Repository.FilterCommits.Default
-- Text.Repository.FilterCommits.Exclude
-- Text.Repository.FilterCommits.Include
-- Text.Repository.HistoriesOrder
-- Text.Repository.HistoriesOrder.ByDate
-- Text.Repository.HistoriesOrder.Topo
-- Text.Repository.Skip
-- Text.ScanRepositories
-- Text.SHALinkCM.NavigateTo
-- Text.WorkingCopy.CommitToEdit
+- Text.Repository.Search.ByContent
+- Text.Repository.ShowSubmodulesAsTree
+- Text.Repository.ViewLogs
+- Text.Repository.Visit
+- Text.ResetWithoutCheckout
+- Text.ResetWithoutCheckout.MoveTo
+- Text.ResetWithoutCheckout.Target
+- Text.Submodule.Deinit
+- Text.Submodule.Status
+- Text.Submodule.Status.Modified
+- Text.Submodule.Status.NotInited
+- Text.Submodule.Status.RevisionChanged
+- Text.Submodule.Status.Unmerged
+- Text.Submodule.URL
+- Text.ViewLogs
+- Text.ViewLogs.Clear
+- Text.ViewLogs.CopyLog
+- Text.ViewLogs.Delete
+- Text.WorkingCopy.ConfirmCommitWithFilter
+- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
+- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
+- Text.WorkingCopy.Conflicts.UseMine
+- Text.WorkingCopy.Conflicts.UseTheirs
+- Text.WorkingCopy.ResetAuthor
-### it_IT.axaml: 95.56%
-
+### 
-Missing Keys
+Missing keys in pt_BR.axaml
+- Text.AIAssistant.Regen
+- Text.AIAssistant.Use
+- Text.ApplyStash
+- Text.ApplyStash.DropAfterApply
+- Text.ApplyStash.RestoreIndex
+- Text.ApplyStash.Stash
+- Text.Avatar.Load
+- Text.Bisect
+- Text.Bisect.Abort
+- Text.Bisect.Bad
+- Text.Bisect.Detecting
+- Text.Bisect.Good
+- Text.Bisect.Skip
+- Text.Bisect.WaitingForRange
+- Text.BranchCM.CustomAction
- Text.BranchCM.MergeMultiBranches
+- Text.BranchCM.ResetToSelectedCommit
+- Text.BranchUpstreamInvalid
+- Text.Checkout.RecurseSubmodules
+- Text.Clone.RecurseSubmodules
+- Text.CommitCM.CopyAuthor
+- Text.CommitCM.CopyCommitter
+- Text.CommitCM.CopySubject
- Text.CommitCM.Merge
- Text.CommitCM.MergeMultiple
+- Text.CommitDetail.Changes.Count
- Text.CommitDetail.Files.Search
- Text.CommitDetail.Info.Children
-- Text.Configure.IssueTracker.AddSampleGitLabMergeRequest
-- Text.Configure.OpenAI.Preferred
-- Text.Configure.OpenAI.Preferred.Tip
+- Text.CommitMessageTextBox.SubjectCount
+- Text.Configure.CustomAction.Scope.Branch
+- Text.Configure.CustomAction.WaitForExit
+- Text.Configure.Git.PreferredMergeMode
+- Text.Configure.IssueTracker.AddSampleGiteeIssue
+- Text.Configure.IssueTracker.AddSampleGiteePullRequest
+- Text.ConfirmEmptyCommit.Continue
+- Text.ConfirmEmptyCommit.NoLocalChanges
+- Text.ConfirmEmptyCommit.StageAllThenCommit
+- Text.ConfirmEmptyCommit.WithLocalChanges
+- Text.CopyFullPath
+- Text.CreateBranch.Name.WarnSpace
+- Text.CreateBranch.OverwriteExisting
+- Text.DeinitSubmodule
+- Text.DeinitSubmodule.Force
+- Text.DeinitSubmodule.Path
+- Text.DeleteRepositoryNode.Path
+- Text.DeleteRepositoryNode.TipForGroup
+- Text.DeleteRepositoryNode.TipForRepository
+- Text.Diff.First
+- Text.Diff.Last
+- Text.Diff.Submodule.Deleted
- Text.Diff.UseBlockNavigation
- Text.Fetch.Force
- Text.FileCM.ResolveUsing
+- Text.GitFlow.FinishWithPush
+- Text.GitFlow.FinishWithSquash
+- Text.Hotkeys.Global.Clone
+- Text.Hotkeys.Global.SwitchWorkspace
+- Text.Hotkeys.Global.SwitchTab
+- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.InProgress.CherryPick.Head
- Text.InProgress.Merge.Operating
- Text.InProgress.Rebase.StoppedAt
- Text.InProgress.Revert.Head
+- Text.Launcher.Workspaces
+- Text.Launcher.Pages
- Text.Merge.Source
- Text.MergeMultiple
- Text.MergeMultiple.CommitChanges
- Text.MergeMultiple.Strategy
- Text.MergeMultiple.Targets
-- Text.Preference.General.ShowChildren
+- Text.Preferences.AI.Streaming
+- Text.Preferences.Appearance.EditorTabWidth
+- Text.Preferences.General.DateFormat
+- Text.Preferences.General.ShowChildren
+- Text.Preferences.General.ShowTagsInGraph
+- Text.Preferences.Git.IgnoreCRAtEOLInDiff
+- Text.Preferences.Git.SSLVerify
+- Text.Pull.RecurseSubmodules
+- Text.Repository.BranchSort
+- Text.Repository.BranchSort.ByCommitterDate
+- Text.Repository.BranchSort.ByName
+- Text.Repository.ClearStashes
- Text.Repository.FilterCommits
-- Text.Repository.FilterCommits.Default
-- Text.Repository.FilterCommits.Exclude
-- Text.Repository.FilterCommits.Include
+- Text.Repository.HistoriesLayout
+- Text.Repository.HistoriesLayout.Horizontal
+- Text.Repository.HistoriesLayout.Vertical
- Text.Repository.HistoriesOrder
-- Text.Repository.HistoriesOrder.ByDate
-- Text.Repository.HistoriesOrder.Topo
+- Text.Repository.Notifications.Clear
+- Text.Repository.OnlyHighlightCurrentBranchInHistories
+- Text.Repository.Search.ByContent
+- Text.Repository.ShowSubmodulesAsTree
- Text.Repository.Skip
-- Text.SHALinkCM.CopySHA
+- Text.Repository.Tags.OrderByCreatorDate
+- Text.Repository.Tags.OrderByName
+- Text.Repository.Tags.Sort
+- Text.Repository.UseRelativeTimeInHistories
+- Text.Repository.ViewLogs
+- Text.Repository.Visit
+- Text.ResetWithoutCheckout
+- Text.ResetWithoutCheckout.MoveTo
+- Text.ResetWithoutCheckout.Target
+- Text.SetUpstream
+- Text.SetUpstream.Local
+- Text.SetUpstream.Unset
+- Text.SetUpstream.Upstream
- Text.SHALinkCM.NavigateTo
+- Text.Stash.AutoRestore
+- Text.Stash.AutoRestore.Tip
+- Text.StashCM.SaveAsPatch
+- Text.Submodule.Deinit
+- Text.Submodule.Status
+- Text.Submodule.Status.Modified
+- Text.Submodule.Status.NotInited
+- Text.Submodule.Status.RevisionChanged
+- Text.Submodule.Status.Unmerged
+- Text.Submodule.URL
+- Text.ViewLogs
+- Text.ViewLogs.Clear
+- Text.ViewLogs.CopyLog
+- Text.ViewLogs.Delete
- Text.WorkingCopy.CommitToEdit
+- Text.WorkingCopy.ConfirmCommitWithFilter
+- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
+- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
+- Text.WorkingCopy.Conflicts.UseMine
+- Text.WorkingCopy.Conflicts.UseTheirs
+- Text.WorkingCopy.ResetAuthor
+- Text.WorkingCopy.SignOff
-### pt_BR.axaml: 96.81%
+### 
+### 
-Missing Keys
+Missing keys in ta_IN.axaml
-- Text.BranchCM.MergeMultiBranches
-- Text.CommitCM.Merge
-- Text.CommitCM.MergeMultiple
-- Text.CommitDetail.Files.Search
-- Text.CommitDetail.Info.Children
-- Text.Diff.UseBlockNavigation
-- Text.Fetch.Force
-- Text.FileCM.ResolveUsing
-- Text.Hotkeys.Global.Clone
-- Text.InProgress.CherryPick.Head
-- Text.InProgress.Merge.Operating
-- Text.InProgress.Rebase.StoppedAt
-- Text.InProgress.Revert.Head
-- Text.Merge.Source
-- Text.MergeMultiple
-- Text.MergeMultiple.CommitChanges
-- Text.MergeMultiple.Strategy
-- Text.MergeMultiple.Targets
-- Text.Preference.General.ShowChildren
-- Text.Repository.FilterCommits
-- Text.Repository.Skip
-- Text.SHALinkCM.NavigateTo
-- Text.WorkingCopy.CommitToEdit
+- Text.Avatar.Load
+- Text.Bisect
+- Text.Bisect.Abort
+- Text.Bisect.Bad
+- Text.Bisect.Detecting
+- Text.Bisect.Good
+- Text.Bisect.Skip
+- Text.Bisect.WaitingForRange
+- Text.BranchCM.CompareWithCurrent
+- Text.BranchCM.ResetToSelectedCommit
+- Text.Checkout.RecurseSubmodules
+- Text.CommitCM.CopyAuthor
+- Text.CommitCM.CopyCommitter
+- Text.CommitCM.CopySubject
+- Text.CommitDetail.Changes.Count
+- Text.CommitMessageTextBox.SubjectCount
+- Text.Configure.Git.PreferredMergeMode
+- Text.ConfirmEmptyCommit.Continue
+- Text.ConfirmEmptyCommit.NoLocalChanges
+- Text.ConfirmEmptyCommit.StageAllThenCommit
+- Text.ConfirmEmptyCommit.WithLocalChanges
+- Text.CreateBranch.OverwriteExisting
+- Text.DeinitSubmodule
+- Text.DeinitSubmodule.Force
+- Text.DeinitSubmodule.Path
+- Text.Diff.Submodule.Deleted
+- Text.GitFlow.FinishWithPush
+- Text.GitFlow.FinishWithSquash
+- Text.Hotkeys.Global.SwitchWorkspace
+- Text.Hotkeys.Global.SwitchTab
+- Text.Hotkeys.TextEditor.OpenExternalMergeTool
+- Text.Launcher.Workspaces
+- Text.Launcher.Pages
+- Text.Preferences.Git.IgnoreCRAtEOLInDiff
+- Text.Pull.RecurseSubmodules
+- Text.Repository.BranchSort
+- Text.Repository.BranchSort.ByCommitterDate
+- Text.Repository.BranchSort.ByName
+- Text.Repository.ClearStashes
+- Text.Repository.Search.ByContent
+- Text.Repository.ShowSubmodulesAsTree
+- Text.Repository.ViewLogs
+- Text.Repository.Visit
+- Text.ResetWithoutCheckout
+- Text.ResetWithoutCheckout.MoveTo
+- Text.ResetWithoutCheckout.Target
+- Text.Submodule.Deinit
+- Text.Submodule.Status
+- Text.Submodule.Status.Modified
+- Text.Submodule.Status.NotInited
+- Text.Submodule.Status.RevisionChanged
+- Text.Submodule.Status.Unmerged
+- Text.Submodule.URL
+- Text.UpdateSubmodules.Target
+- Text.ViewLogs
+- Text.ViewLogs.Clear
+- Text.ViewLogs.CopyLog
+- Text.ViewLogs.Delete
+- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
+- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
+- Text.WorkingCopy.Conflicts.UseMine
+- Text.WorkingCopy.Conflicts.UseTheirs
+- Text.WorkingCopy.ResetAuthor
-### ru_RU.axaml: 97.92%
-
+### 
-Missing Keys
+Missing keys in uk_UA.axaml
-- Text.BranchCM.MergeMultiBranches
-- Text.CommitCM.Merge
-- Text.CommitCM.MergeMultiple
-- Text.FileCM.ResolveUsing
-- Text.Hotkeys.Global.Clone
-- Text.InProgress.CherryPick.Head
-- Text.InProgress.Merge.Operating
-- Text.InProgress.Rebase.StoppedAt
-- Text.InProgress.Revert.Head
-- Text.Merge.Source
-- Text.MergeMultiple
-- Text.MergeMultiple.CommitChanges
-- Text.MergeMultiple.Strategy
-- Text.MergeMultiple.Targets
-- Text.Repository.Skip
+- Text.Avatar.Load
+- Text.Bisect
+- Text.Bisect.Abort
+- Text.Bisect.Bad
+- Text.Bisect.Detecting
+- Text.Bisect.Good
+- Text.Bisect.Skip
+- Text.Bisect.WaitingForRange
+- Text.BranchCM.ResetToSelectedCommit
+- Text.Checkout.RecurseSubmodules
+- Text.CommitCM.CopyAuthor
+- Text.CommitCM.CopyCommitter
+- Text.CommitCM.CopySubject
+- Text.CommitDetail.Changes.Count
+- Text.CommitMessageTextBox.SubjectCount
+- Text.ConfigureWorkspace.Name
+- Text.CreateBranch.OverwriteExisting
+- Text.DeinitSubmodule
+- Text.DeinitSubmodule.Force
+- Text.DeinitSubmodule.Path
+- Text.Diff.Submodule.Deleted
+- Text.GitFlow.FinishWithPush
+- Text.GitFlow.FinishWithSquash
+- Text.Hotkeys.Global.SwitchWorkspace
+- Text.Hotkeys.Global.SwitchTab
+- Text.Hotkeys.TextEditor.OpenExternalMergeTool
+- Text.Launcher.Workspaces
+- Text.Launcher.Pages
+- Text.Preferences.Git.IgnoreCRAtEOLInDiff
+- Text.Pull.RecurseSubmodules
+- Text.Repository.BranchSort
+- Text.Repository.BranchSort.ByCommitterDate
+- Text.Repository.BranchSort.ByName
+- Text.Repository.ClearStashes
+- Text.Repository.Search.ByContent
+- Text.Repository.ShowSubmodulesAsTree
+- Text.Repository.ViewLogs
+- Text.Repository.Visit
+- Text.ResetWithoutCheckout
+- Text.ResetWithoutCheckout.MoveTo
+- Text.ResetWithoutCheckout.Target
+- Text.Submodule.Deinit
+- Text.Submodule.Status
+- Text.Submodule.Status.Modified
+- Text.Submodule.Status.NotInited
+- Text.Submodule.Status.RevisionChanged
+- Text.Submodule.Status.Unmerged
+- Text.Submodule.URL
+- Text.ViewLogs
+- Text.ViewLogs.Clear
+- Text.ViewLogs.CopyLog
+- Text.ViewLogs.Delete
+- Text.WorkingCopy.ResetAuthor
-### zh_CN.axaml: 100.00%
+### 
-
-
-Missing Keys
-
-
-
-
-
-### zh_TW.axaml: 100.00%
-
-
-
-Missing Keys
-
-
-
-
+### 
\ No newline at end of file
diff --git a/VERSION b/VERSION
index 50a1eb5b..b89504d0 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-8.43
\ No newline at end of file
+2025.21
\ No newline at end of file
diff --git a/build/README.md b/build/README.md
index b4358a55..17305edf 100644
--- a/build/README.md
+++ b/build/README.md
@@ -12,4 +12,4 @@
dotnet publish -c Release -r $RUNTIME_IDENTIFIER -o $DESTINATION_FOLDER src/SourceGit.csproj
```
> [!NOTE]
-> Please replace the `$RUNTIME_IDENTIFIER` with one of `win-x64`,`win-arm64`,`linux-x64`,`linux-arm64`,`osx-x64`,`osx-arm64`, and replece the `$DESTINATION_FOLDER` with the real path that will store the output executable files.
+> Please replace the `$RUNTIME_IDENTIFIER` with one of `win-x64`,`win-arm64`,`linux-x64`,`linux-arm64`,`osx-x64`,`osx-arm64`, and replace the `$DESTINATION_FOLDER` with the real path that will store the output executable files.
diff --git a/build/resources/deb/DEBIAN/control b/build/resources/deb/DEBIAN/control
index 7cfed330..71786b43 100755
--- a/build/resources/deb/DEBIAN/control
+++ b/build/resources/deb/DEBIAN/control
@@ -1,7 +1,8 @@
Package: sourcegit
-Version: 8.23
+Version: 2025.10
Priority: optional
-Depends: libx11-6, libice6, libsm6
+Depends: libx11-6, libice6, libsm6, libicu | libicu76 | libicu74 | libicu72 | libicu71 | libicu70 | libicu69 | libicu68 | libicu67 | libicu66 | libicu65 | libicu63 | libicu60 | libicu57 | libicu55 | libicu52, xdg-utils
Architecture: amd64
+Installed-Size: 60440
Maintainer: longshuang@msn.cn
Description: Open-source & Free Git GUI Client
diff --git a/build/resources/deb/DEBIAN/preinst b/build/resources/deb/DEBIAN/preinst
new file mode 100755
index 00000000..a93f8090
--- /dev/null
+++ b/build/resources/deb/DEBIAN/preinst
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+set -e
+
+# summary of how this script can be called:
+# * `install'
+# * `install'
+# * `upgrade'
+# * `abort-upgrade'
+# for details, see http://www.debian.org/doc/debian-policy/
+
+case "$1" in
+ install|upgrade)
+ # Check if SourceGit is running and stop it
+ if pgrep -f '/opt/sourcegit/sourcegit' > /dev/null; then
+ echo "Stopping running SourceGit instance..."
+ pkill -f '/opt/sourcegit/sourcegit' || true
+ # Give the process a moment to terminate
+ sleep 1
+ fi
+ ;;
+
+ abort-upgrade)
+ ;;
+
+ *)
+ echo "preinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/build/resources/deb/DEBIAN/prerm b/build/resources/deb/DEBIAN/prerm
new file mode 100755
index 00000000..c2c9e4f0
--- /dev/null
+++ b/build/resources/deb/DEBIAN/prerm
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+set -e
+
+# summary of how this script can be called:
+# * `remove'
+# * `upgrade'
+# * `failed-upgrade'
+# * `remove' `in-favour'
+# * `deconfigure' `in-favour'
+# `removing'
+#
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+case "$1" in
+ remove|upgrade|deconfigure)
+ if pgrep -f '/opt/sourcegit/sourcegit' > /dev/null; then
+ echo "Stopping running SourceGit instance..."
+ pkill -f '/opt/sourcegit/sourcegit' || true
+ # Give the process a moment to terminate
+ sleep 1
+ fi
+ ;;
+
+ failed-upgrade)
+ ;;
+
+ *)
+ echo "prerm called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/build/resources/rpm/SPECS/build.spec b/build/resources/rpm/SPECS/build.spec
index bc10ca48..2a684837 100644
--- a/build/resources/rpm/SPECS/build.spec
+++ b/build/resources/rpm/SPECS/build.spec
@@ -8,6 +8,7 @@ Source: https://github.com/sourcegit-scm/sourcegit/archive/refs/tags/v%_version.
Requires: libX11.so.6()(%{__isa_bits}bit)
Requires: libSM.so.6()(%{__isa_bits}bit)
Requires: libicu
+Requires: xdg-utils
%define _build_id_links none
diff --git a/build/scripts/localization-check.js b/build/scripts/localization-check.js
index 45db82be..8d636b5b 100644
--- a/build/scripts/localization-check.js
+++ b/build/scripts/localization-check.js
@@ -6,7 +6,6 @@ const repoRoot = path.join(__dirname, '../../');
const localesDir = path.join(repoRoot, 'src/Resources/Locales');
const enUSFile = path.join(localesDir, 'en_US.axaml');
const outputFile = path.join(repoRoot, 'TRANSLATION.md');
-const readmeFile = path.join(repoRoot, 'README.md');
const parser = new xml2js.Parser();
@@ -15,45 +14,70 @@ async function parseXml(filePath) {
return parser.parseStringPromise(data);
}
+async function filterAndSortTranslations(localeData, enUSKeys, enUSData) {
+ const strings = localeData.ResourceDictionary['x:String'];
+ // Remove keys that don't exist in English file
+ const filtered = strings.filter(item => enUSKeys.has(item.$['x:Key']));
+
+ // Sort based on the key order in English file
+ const enUSKeysArray = enUSData.ResourceDictionary['x:String'].map(item => item.$['x:Key']);
+ filtered.sort((a, b) => {
+ const aIndex = enUSKeysArray.indexOf(a.$['x:Key']);
+ const bIndex = enUSKeysArray.indexOf(b.$['x:Key']);
+ return aIndex - bIndex;
+ });
+
+ return filtered;
+}
+
async function calculateTranslationRate() {
const enUSData = await parseXml(enUSFile);
const enUSKeys = new Set(enUSData.ResourceDictionary['x:String'].map(item => item.$['x:Key']));
-
- const translationRates = [];
- const badges = [];
-
const files = (await fs.readdir(localesDir)).filter(file => file !== 'en_US.axaml' && file.endsWith('.axaml'));
- // Add en_US badge first
- badges.push(`[](TRANSLATION.md)`);
+ const lines = [];
+
+ lines.push('# Translation Status');
+ lines.push('This document shows the translation status of each locale file in the repository.');
+ lines.push(`## Details`);
+ lines.push(`### `);
for (const file of files) {
+ const locale = file.replace('.axaml', '').replace('_', '__');
const filePath = path.join(localesDir, file);
const localeData = await parseXml(filePath);
const localeKeys = new Set(localeData.ResourceDictionary['x:String'].map(item => item.$['x:Key']));
-
const missingKeys = [...enUSKeys].filter(key => !localeKeys.has(key));
- const translationRate = ((enUSKeys.size - missingKeys.length) / enUSKeys.size) * 100;
- translationRates.push(`### ${file}: ${translationRate.toFixed(2)}%\n`);
- translationRates.push(`\nMissing Keys
\n\n${missingKeys.map(key => `- ${key}`).join('\n')}\n\n `);
+ // Sort and clean up extra translations
+ const sortedAndCleaned = await filterAndSortTranslations(localeData, enUSKeys, enUSData);
+ localeData.ResourceDictionary['x:String'] = sortedAndCleaned;
- // Add badges
- const locale = file.replace('.axaml', '').replace('_', '__');
- const badgeColor = translationRate === 100 ? 'brightgreen' : translationRate >= 75 ? 'yellow' : 'red';
- badges.push(`[}%25-${badgeColor})](TRANSLATION.md)`);
+ // Save the updated file
+ const builder = new xml2js.Builder({
+ headless: true,
+ renderOpts: { pretty: true, indent: ' ' }
+ });
+ let xmlStr = builder.buildObject(localeData);
+
+ // Add an empty line before the first x:String
+ xmlStr = xmlStr.replace(' 0) {
+ const progress = ((enUSKeys.size - missingKeys.length) / enUSKeys.size) * 100;
+ const badgeColor = progress >= 75 ? 'yellow' : 'red';
+
+ lines.push(`### }%25-${badgeColor})`);
+ lines.push(`\nMissing keys in ${file}
\n\n${missingKeys.map(key => `- ${key}`).join('\n')}\n\n `)
+ } else {
+ lines.push(`### `);
+ }
}
- console.log(translationRates.join('\n\n'));
-
- await fs.writeFile(outputFile, translationRates.join('\n\n') + '\n', 'utf8');
-
- // Update README.md
- let readmeContent = await fs.readFile(readmeFile, 'utf8');
- const badgeSection = `## Translation Status\n\n${badges.join(' ')}`;
- console.log(badgeSection);
- readmeContent = readmeContent.replace(/## Translation Status\n\n.*\n\n/, badgeSection + '\n\n');
- await fs.writeFile(readmeFile, readmeContent, 'utf8');
+ const content = lines.join('\n\n');
+ console.log(content);
+ await fs.writeFile(outputFile, content, 'utf8');
}
calculateTranslationRate().catch(err => console.error(err));
diff --git a/build/scripts/package.linux.sh b/build/scripts/package.linux.sh
index 5abb058b..1b4adbdc 100755
--- a/build/scripts/package.linux.sh
+++ b/build/scripts/package.linux.sh
@@ -56,8 +56,15 @@ cp -f SourceGit/* resources/deb/opt/sourcegit
ln -rsf resources/deb/opt/sourcegit/sourcegit resources/deb/usr/bin
cp -r resources/_common/applications resources/deb/usr/share
cp -r resources/_common/icons resources/deb/usr/share
-sed -i -e "s/^Version:.*/Version: $VERSION/" -e "s/^Architecture:.*/Architecture: $arch/" resources/deb/DEBIAN/control
-dpkg-deb --root-owner-group --build resources/deb "sourcegit_$VERSION-1_$arch.deb"
+# Calculate installed size in KB
+installed_size=$(du -sk resources/deb | cut -f1)
+# Update the control file
+sed -i -e "s/^Version:.*/Version: $VERSION/" \
+ -e "s/^Architecture:.*/Architecture: $arch/" \
+ -e "s/^Installed-Size:.*/Installed-Size: $installed_size/" \
+ resources/deb/DEBIAN/control
+# Build deb package with gzip compression
+dpkg-deb -Zgzip --root-owner-group --build resources/deb "sourcegit_$VERSION-1_$arch.deb"
rpmbuild -bb --target="$target" resources/rpm/SPECS/build.spec --define "_topdir $(pwd)/resources/rpm" --define "_version $VERSION"
mv "resources/rpm/RPMS/$target/sourcegit-$VERSION-1.$target.rpm" ./
diff --git a/build/scripts/package.windows-portable.sh b/build/scripts/package.windows-portable.sh
deleted file mode 100755
index 6bd3879b..00000000
--- a/build/scripts/package.windows-portable.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-set -o
-set -u
-set pipefail
-
-cd build
-
-rm -rf SourceGit/*.pdb
-
-zip "sourcegit_$VERSION.$RUNTIME.zip" -r SourceGit
diff --git a/build/scripts/package.windows.sh b/build/scripts/package.windows.sh
new file mode 100755
index 00000000..c22a9d35
--- /dev/null
+++ b/build/scripts/package.windows.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+set -e
+set -o
+set -u
+set pipefail
+
+cd build
+
+rm -rf SourceGit/*.pdb
+
+if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OSTYPE" == "win32" ]]; then
+ powershell -Command "Compress-Archive -Path SourceGit -DestinationPath \"sourcegit_$VERSION.$RUNTIME.zip\" -Force"
+else
+ zip "sourcegit_$VERSION.$RUNTIME.zip" -r SourceGit
+fi
diff --git a/src/App.Commands.cs b/src/App.Commands.cs
index 8a485029..22e9fb51 100644
--- a/src/App.Commands.cs
+++ b/src/App.Commands.cs
@@ -25,12 +25,34 @@ namespace SourceGit
private Action