From 32de28c16e59eeb8d7be7eacc160355b11024f31 Mon Sep 17 00:00:00 2001 From: GadflyFang Date: Fri, 25 Oct 2024 14:22:38 +0800 Subject: [PATCH] ci: add Localization Check CI (#600) Signed-off-by: Gadfly --- .editorconfig | 5 + .github/scripts/localization-check.js | 59 ++++++++ .github/workflows/localization-check.yml | 42 ++++++ .gitignore | 6 +- README.md | 4 + SourceGit.sln | 1 + TRANSLATION.md | 184 +++++++++++++++++++++++ 7 files changed, 300 insertions(+), 1 deletion(-) create mode 100644 .github/scripts/localization-check.js create mode 100644 .github/workflows/localization-check.yml create mode 100644 TRANSLATION.md diff --git a/.editorconfig b/.editorconfig index dedc5722..3ad9d05b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -292,3 +292,8 @@ indent_size = 2 end_of_line = lf [*.{cmd,bat}] end_of_line = crlf + +# YAML files +[*.{yml,yaml}] +indent_size = 2 +end_of_line = lf diff --git a/.github/scripts/localization-check.js b/.github/scripts/localization-check.js new file mode 100644 index 00000000..4841e3d6 --- /dev/null +++ b/.github/scripts/localization-check.js @@ -0,0 +1,59 @@ +const fs = require('fs-extra'); +const path = require('path'); +const xml2js = require('xml2js'); + +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(); + +async function parseXml(filePath) { + const data = await fs.readFile(filePath); + return parser.parseStringPromise(data); +} + +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(`![en_US](https://img.shields.io/badge/en__US-100%25-brightgreen)`); + + for (const file of files) { + 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
`); + + // Add badges + const locale = file.replace('.axaml', '').replace('_', '__'); + const badgeColor = translationRate === 100 ? 'brightgreen' : translationRate >= 75 ? 'yellow' : 'red'; + badges.push(`![${locale}](https://img.shields.io/badge/${locale}-${translationRate.toFixed(2)}%25-${badgeColor})`); + } + + console.log(translationRates.join('\n\n')); + + await fs.writeFile(outputFile, translationRates.join('\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'); +} + +calculateTranslationRate().catch(err => console.error(err)); diff --git a/.github/workflows/localization-check.yml b/.github/workflows/localization-check.yml new file mode 100644 index 00000000..d5ebe8c3 --- /dev/null +++ b/.github/workflows/localization-check.yml @@ -0,0 +1,42 @@ +name: Localization Check +on: + push: + branches: [ develop ] + paths: + - 'src/Resources/Locales/**' + - 'README.md' + workflow_dispatch: + workflow_call: + +jobs: + localization-check: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Install dependencies + run: npm install fs-extra@11.2.0 path@0.12.7 xml2js@0.6.2 + + - name: Run localization check + run: node .github/scripts/localization-check.js + + - name: Commit changes + run: | + 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 push + else + echo "No changes to commit" + fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 95bde92d..0c66b11e 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,10 @@ ehthumbs_vista.db bin/ obj/ +# ignore ci node files +node_modules/ +package.json +package-lock.json build/resources/ build/SourceGit/ @@ -32,4 +36,4 @@ build/*.tar.gz build/*.deb build/*.rpm build/*.AppImage -SourceGit.app/ \ No newline at end of file +SourceGit.app/ diff --git a/README.md b/README.md index 62427db4..31532e01 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,10 @@ > [!WARNING] > **Linux** only tested on **Debian 12** on both **X11** & **Wayland**. +## Translation Status + +![en_US](https://img.shields.io/badge/en__US-100%25-brightgreen) ![de__DE](https://img.shields.io/badge/de__DE-98.95%25-yellow) ![fr__FR](https://img.shields.io/badge/fr__FR-90.38%25-yellow) ![pt__BR](https://img.shields.io/badge/pt__BR-93.53%25-yellow) ![ru__RU](https://img.shields.io/badge/ru__RU-98.80%25-yellow) ![zh__CN](https://img.shields.io/badge/zh__CN-98.95%25-yellow) ![zh__TW](https://img.shields.io/badge/zh__TW-99.70%25-yellow) + ## How to Use **To use this tool, you need to install Git(>=2.23.0) first.** diff --git a/SourceGit.sln b/SourceGit.sln index 10c94e36..abd42aee 100644 --- a/SourceGit.sln +++ b/SourceGit.sln @@ -16,6 +16,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{ .github\workflows\ci.yml = .github\workflows\ci.yml .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 EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{49A7C2D6-558C-4FAA-8F5D-EEE81497AED7}" diff --git a/TRANSLATION.md b/TRANSLATION.md new file mode 100644 index 00000000..2cac2dec --- /dev/null +++ b/TRANSLATION.md @@ -0,0 +1,184 @@ +### de_DE.axaml: 98.95% + + +
+Missing Keys + +- Text.Configure.Git.EnableSignOff +- Text.Configure.IssueTracker.AddSampleGitLabIssue +- Text.Configure.IssueTracker.AddSampleGitLabMergeRequest +- Text.Preference.Advanced +- Text.Preference.AI.AnalyzeDiffPrompt +- Text.Preference.AI.GenerateSubjectPrompt +- Text.WorkingCopy.ConfirmCommitWithoutFiles + +
+ +### fr_FR.axaml: 90.38% + + +
+Missing Keys + +- Text.About.Chart +- Text.AIAssistant +- Text.AIAssistant.Tip +- Text.CherryPick.AppendSourceToMessage +- Text.CherryPick.Mainline +- Text.CherryPick.Mainline.Tips +- Text.CommitCM.CherryPickMultiple +- Text.CommitCM.SquashCommitsSinceThis +- Text.CommitDetail.Info.WebLinks +- Text.Configure.Git.DefaultRemote +- Text.Configure.Git.EnableSignOff +- Text.Configure.IssueTracker.AddSampleGitLabIssue +- Text.Configure.IssueTracker.AddSampleGitLabMergeRequest +- Text.ConfigureWorkspace +- Text.ConfigureWorkspace.Color +- Text.ConfigureWorkspace.Restore +- Text.ConventionalCommit +- Text.ConventionalCommit.BreakingChanges +- Text.ConventionalCommit.ClosedIssue +- Text.ConventionalCommit.Detail +- Text.ConventionalCommit.Scope +- Text.ConventionalCommit.ShortDescription +- Text.ConventionalCommit.Type +- Text.Diff.IgnoreWhitespace +- Text.Discard.IncludeIgnored +- Text.FileHistory.FileChange +- Text.GitLFS.Locks.OnlyMine +- Text.Histories.Header.AuthorTime +- Text.Histories.Tips +- Text.Histories.Tips.MacOS +- Text.Histories.Tips.Prefix +- Text.Hotkeys.Repo.CommitWithAutoStage +- Text.Hotkeys.Repo.DiscardSelected +- Text.MoveRepositoryNode +- Text.MoveRepositoryNode.Target +- Text.Preference.Advanced +- Text.Preference.AI +- Text.Preference.AI.AnalyzeDiffPrompt +- Text.Preference.AI.ApiKey +- Text.Preference.AI.GenerateSubjectPrompt +- Text.Preference.AI.Model +- Text.Preference.AI.Server +- Text.Preference.General.ShowAuthorTime +- Text.Preference.Integration +- Text.Preference.Shell +- Text.Preference.Shell.Type +- Text.Preference.Shell.Path +- Text.Repository.AutoFetching +- Text.Repository.EnableReflog +- Text.Repository.Search.InCurrentBranch +- Text.ScanRepositories +- Text.ScanRepositories.RootDir +- Text.Squash.Into +- Text.Stash.OnlyStagedChanges +- Text.Stash.TipForSelectedFiles +- Text.Statistics.Overview +- Text.TagCM.CopyMessage +- Text.Welcome.Move +- Text.Welcome.ScanDefaultCloneDir +- Text.WorkingCopy.CommitTip +- Text.WorkingCopy.CommitWithAutoStage +- Text.WorkingCopy.ConfirmCommitWithoutFiles +- Text.Workspace +- Text.Workspace.Configure + +
+ +### pt_BR.axaml: 93.53% + + +
+Missing Keys + +- Text.About.Chart +- Text.AIAssistant +- Text.AIAssistant.Tip +- Text.CherryPick.AppendSourceToMessage +- Text.CherryPick.Mainline +- Text.CherryPick.Mainline.Tips +- Text.CommitCM.CherryPickMultiple +- Text.CommitCM.SquashCommitsSinceThis +- Text.CommitDetail.Info.ContainsIn +- Text.CommitDetail.Info.ContainsIn.Title +- Text.CommitDetail.Info.WebLinks +- Text.Configure.Git.DefaultRemote +- Text.Configure.Git.EnableSignOff +- Text.Configure.IssueTracker.AddSampleGitLabIssue +- Text.Configure.IssueTracker.AddSampleGitLabMergeRequest +- Text.ConfigureWorkspace +- Text.ConfigureWorkspace.Color +- Text.ConfigureWorkspace.Restore +- Text.ConventionalCommit +- Text.ConventionalCommit.BreakingChanges +- Text.ConventionalCommit.ClosedIssue +- Text.ConventionalCommit.Detail +- Text.ConventionalCommit.Scope +- Text.ConventionalCommit.ShortDescription +- Text.ConventionalCommit.Type +- Text.CopyAllText +- Text.Discard.IncludeIgnored +- Text.FileHistory.FileContent +- Text.FileHistory.FileChange +- Text.GitLFS.Locks.OnlyMine +- Text.MoveRepositoryNode +- Text.MoveRepositoryNode.Target +- Text.Preference.Advanced +- Text.Push.CheckSubmodules +- Text.Squash.Into +- Text.Stash.OnlyStagedChanges +- Text.Stash.TipForSelectedFiles +- Text.Statistics.Overview +- Text.TagCM.CopyMessage +- Text.WorkingCopy.Staged.UnstageAll +- Text.WorkingCopy.Unstaged +- Text.WorkingCopy.Unstaged.Stage +- Text.WorkingCopy.Unstaged.StageAll + +
+ +### ru_RU.axaml: 98.80% + + +
+Missing Keys + +- Text.Configure.Git.EnableSignOff +- Text.Configure.IssueTracker.AddSampleGitLabIssue +- Text.Configure.IssueTracker.AddSampleGitLabMergeRequest +- Text.Preference.Advanced +- Text.Preference.AI.AnalyzeDiffPrompt +- Text.Preference.AI.GenerateSubjectPrompt +- Text.Repository.EnableReflog +- Text.WorkingCopy.ConfirmCommitWithoutFiles + +
+ +### zh_CN.axaml: 98.95% + + +
+Missing Keys + +- Text.Preference.AI +- Text.Preference.AI.AnalyzeDiffPrompt +- Text.Preference.AI.ApiKey +- Text.Preference.AI.GenerateSubjectPrompt +- Text.Preference.AI.Model +- Text.Preference.AI.Server +- Text.RemoteCM.Prune.Target + +
+ +### zh_TW.axaml: 99.70% + + +
+Missing Keys + +- Text.Preference.AI.AnalyzeDiffPrompt +- Text.Preference.AI.GenerateSubjectPrompt + +