A tool to help to backport locales, changes source strings to fix other broken translations (#23633)
It use old en-US locales as reference, fill the old other locales with new locales. ---- ## More broken translations Many translations are still broken. The reason is: at the last time restoring the ini to crowdin, many semicolon are treated as comments. Two kinds of broken strings: ### Some translations can be re-translated <details> ``` skipping options/locale/locale_si-LK.ini org teams.add_nonexistent_repo skipping options/locale/locale_tr-TR.ini repo commits.search.tooltip skipping options/locale/locale_es-ES.ini repo settings.trust_model.committer.desc skipping options/locale/locale_es-ES.ini admin dashboard.new_version_hint skipping options/locale/locale_pt-PT.ini org teams.add_nonexistent_repo skipping options/locale/locale_hu-HU.ini install require_sign_in_view_popup skipping options/locale/locale_hu-HU.ini repo migrate.invalid_local_path skipping options/locale/locale_id-ID.ini repo migrate.invalid_local_path skipping options/locale/locale_id-ID.ini org teams.add_nonexistent_repo skipping options/locale/locale_de-DE.ini repo settings.protect_protected_file_patterns_desc ``` </details> So this PR also does some small changes on them, to trigger the re-translation. ### The `locale_el-GR.ini` contains many broken tranlsations I guess we should reset them from crowdin side, then translators can re-translate them. ---- Update: in latest main, the strings have been fixed. ## TODO Update: the el-GR translators have done great job and fixes these broken translations. <details> Merge this PR ASAP and upload `locale_el-GR.ini` to crowdin to remove broken strings. Out-dated, fixed in main. ![image](https://user-images.githubusercontent.com/2114189/226954531-36e14527-278a-41a1-8ddb-2b2b27bfc746.png) </details> --------- Co-authored-by: delvh <dev.lh@web.de>
This commit is contained in:
parent
378d6b8491
commit
95818adb71
2 changed files with 107 additions and 19 deletions
89
build/backport-locales.go
Normal file
89
build/backport-locales.go
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
//go:build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gopkg.in/ini.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) != 2 {
|
||||||
|
println("usage: backport-locales <to-ref>")
|
||||||
|
println("eg: backport-locales release/v1.19")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
ini.PrettyFormat = false
|
||||||
|
mustNoErr := func(err error) {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
collectInis := func(ref string) map[string]*ini.File {
|
||||||
|
inis := map[string]*ini.File{}
|
||||||
|
err := filepath.WalkDir("options/locale", func(path string, d os.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if d.IsDir() || !strings.HasSuffix(d.Name(), ".ini") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cfg, err := ini.LoadSources(ini.LoadOptions{
|
||||||
|
IgnoreInlineComment: true,
|
||||||
|
UnescapeValueCommentSymbols: true,
|
||||||
|
}, path)
|
||||||
|
mustNoErr(err)
|
||||||
|
inis[path] = cfg
|
||||||
|
fmt.Printf("collecting: %s @ %s\n", path, ref)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
mustNoErr(err)
|
||||||
|
return inis
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect new locales from current working directory
|
||||||
|
inisNew := collectInis("HEAD")
|
||||||
|
|
||||||
|
// switch to the target ref, and collect the old locales
|
||||||
|
cmd := exec.Command("git", "checkout", os.Args[1])
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
mustNoErr(cmd.Run())
|
||||||
|
inisOld := collectInis(os.Args[1])
|
||||||
|
|
||||||
|
// use old en-US as the base, and copy the new translations to the old locales
|
||||||
|
enUsOld := inisOld["options/locale/locale_en-US.ini"]
|
||||||
|
for path, iniOld := range inisOld {
|
||||||
|
if iniOld == enUsOld {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
iniNew := inisNew[path]
|
||||||
|
if iniNew == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, secEnUS := range enUsOld.Sections() {
|
||||||
|
secOld := iniOld.Section(secEnUS.Name())
|
||||||
|
secNew := iniNew.Section(secEnUS.Name())
|
||||||
|
for _, keyEnUs := range secEnUS.Keys() {
|
||||||
|
if secNew.HasKey(keyEnUs.Name()) {
|
||||||
|
oldStr := secOld.Key(keyEnUs.Name()).String()
|
||||||
|
newStr := secNew.Key(keyEnUs.Name()).String()
|
||||||
|
// A bug: many of new translations with ";" are broken in Crowdin (due to last messy restoring)
|
||||||
|
// As the broken strings are gradually fixed, this workaround check could be removed (in a few months?)
|
||||||
|
if strings.Contains(oldStr, ";") && !strings.Contains(newStr, ";") {
|
||||||
|
println("skip potential broken string", path, secEnUS.Name(), keyEnUs.Name())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
secOld.Key(keyEnUs.Name()).SetValue(newStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mustNoErr(iniOld.SaveTo(path))
|
||||||
|
}
|
||||||
|
}
|
|
@ -219,7 +219,7 @@ openid_signup_popup = Enable OpenID-based user self-registration.
|
||||||
enable_captcha = Enable registration CAPTCHA
|
enable_captcha = Enable registration CAPTCHA
|
||||||
enable_captcha_popup = Require a CAPTCHA for user self-registration.
|
enable_captcha_popup = Require a CAPTCHA for user self-registration.
|
||||||
require_sign_in_view = Require Sign-In to View Pages
|
require_sign_in_view = Require Sign-In to View Pages
|
||||||
require_sign_in_view_popup = Limit page access to signed-in users. Visitors will only see the 'sign in' and registration pages.
|
require_sign_in_view_popup = Limit page access to signed-in users. Visitors will only see the sign-in and registration pages.
|
||||||
admin_setting_desc = Creating an administrator account is optional. The first registered user will automatically become an administrator.
|
admin_setting_desc = Creating an administrator account is optional. The first registered user will automatically become an administrator.
|
||||||
admin_title = Administrator Account Settings
|
admin_title = Administrator Account Settings
|
||||||
admin_name = Administrator Username
|
admin_name = Administrator Username
|
||||||
|
@ -249,7 +249,7 @@ no_reply_address = Hidden Email Domain
|
||||||
no_reply_address_helper = Domain name for users with a hidden email address. For example, the username 'joe' will be logged in Git as 'joe@noreply.example.org' if the hidden email domain is set to 'noreply.example.org'.
|
no_reply_address_helper = Domain name for users with a hidden email address. For example, the username 'joe' will be logged in Git as 'joe@noreply.example.org' if the hidden email domain is set to 'noreply.example.org'.
|
||||||
password_algorithm = Password Hash Algorithm
|
password_algorithm = Password Hash Algorithm
|
||||||
invalid_password_algorithm = Invalid password hash algorithm
|
invalid_password_algorithm = Invalid password hash algorithm
|
||||||
password_algorithm_helper = Set the password hashing algorithm. Algorithms have differing requirements and strength. `argon2` whilst having good characteristics uses a lot of memory and may be inappropriate for small systems.
|
password_algorithm_helper = Set the password hashing algorithm. Algorithms have differing requirements and strength. The argon2 algorithm is rather secure but uses a lot of memory and may be inappropriate for small systems.
|
||||||
enable_update_checker = Enable Update Checker
|
enable_update_checker = Enable Update Checker
|
||||||
enable_update_checker_helper = Checks for new version releases periodically by connecting to gitea.io.
|
enable_update_checker_helper = Checks for new version releases periodically by connecting to gitea.io.
|
||||||
|
|
||||||
|
@ -521,14 +521,14 @@ invalid_ssh_key = Cannot verify your SSH key: %s
|
||||||
invalid_gpg_key = Cannot verify your GPG key: %s
|
invalid_gpg_key = Cannot verify your GPG key: %s
|
||||||
invalid_ssh_principal = Invalid principal: %s
|
invalid_ssh_principal = Invalid principal: %s
|
||||||
must_use_public_key = The key you provided is a private key. Please do not upload your private key anywhere. Use your public key instead.
|
must_use_public_key = The key you provided is a private key. Please do not upload your private key anywhere. Use your public key instead.
|
||||||
unable_verify_ssh_key = "Cannot verify the SSH key; double-check it for mistakes."
|
unable_verify_ssh_key = "Cannot verify the SSH key, double-check it for mistakes."
|
||||||
auth_failed = Authentication failed: %v
|
auth_failed = Authentication failed: %v
|
||||||
|
|
||||||
still_own_repo = "Your account owns one or more repositories; delete or transfer them first."
|
still_own_repo = "Your account owns one or more repositories, delete or transfer them first."
|
||||||
still_has_org = "Your account is a member of one or more organizations; leave them first."
|
still_has_org = "Your account is a member of one or more organizations, leave them first."
|
||||||
still_own_packages = "Your account owns one or more packages; delete them first."
|
still_own_packages = "Your account owns one or more packages, delete them first."
|
||||||
org_still_own_repo = "This organization still owns one or more repositories; delete or transfer them first."
|
org_still_own_repo = "This organization still owns one or more repositories, delete or transfer them first."
|
||||||
org_still_own_packages = "This organization still owns one or more packages; delete them first."
|
org_still_own_packages = "This organization still owns one or more packages, delete them first."
|
||||||
|
|
||||||
target_branch_not_exist = Target branch does not exist.
|
target_branch_not_exist = Target branch does not exist.
|
||||||
|
|
||||||
|
@ -993,7 +993,7 @@ migrate.github_token_desc = You can put one or more tokens with comma separated
|
||||||
migrate.clone_local_path = or a local server path
|
migrate.clone_local_path = or a local server path
|
||||||
migrate.permission_denied = You are not allowed to import local repositories.
|
migrate.permission_denied = You are not allowed to import local repositories.
|
||||||
migrate.permission_denied_blocked = You cannot import from disallowed hosts, please ask the admin to check ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS settings.
|
migrate.permission_denied_blocked = You cannot import from disallowed hosts, please ask the admin to check ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS settings.
|
||||||
migrate.invalid_local_path = "The local path is invalid. It does not exist or is not a directory."
|
migrate.invalid_local_path = "The local path is invalid. It doesn't exist or is not a directory."
|
||||||
migrate.invalid_lfs_endpoint = The LFS endpoint is not valid.
|
migrate.invalid_lfs_endpoint = The LFS endpoint is not valid.
|
||||||
migrate.failed = Migration failed: %v
|
migrate.failed = Migration failed: %v
|
||||||
migrate.migrate_items_options = Access Token is required to migrate additional items
|
migrate.migrate_items_options = Access Token is required to migrate additional items
|
||||||
|
@ -1175,7 +1175,7 @@ commits.commits = Commits
|
||||||
commits.no_commits = No commits in common. '%s' and '%s' have entirely different histories.
|
commits.no_commits = No commits in common. '%s' and '%s' have entirely different histories.
|
||||||
commits.nothing_to_compare = These branches are equal.
|
commits.nothing_to_compare = These branches are equal.
|
||||||
commits.search = Search commits…
|
commits.search = Search commits…
|
||||||
commits.search.tooltip = You can prefix keywords with "author:", "committer:", "after:", or "before:", e.g. "revert author:Alice before:2019-04-01".
|
commits.search.tooltip = You can prefix keywords with "author:", "committer:", "after:", or "before:", e.g. "revert author:Alice before:2019-01-13".
|
||||||
commits.find = Search
|
commits.find = Search
|
||||||
commits.search_all = All Branches
|
commits.search_all = All Branches
|
||||||
commits.author = Author
|
commits.author = Author
|
||||||
|
@ -1635,7 +1635,6 @@ pulls.merge_conflict = Merge Failed: There was a conflict whilst merging. Hint:
|
||||||
pulls.merge_conflict_summary = Error Message
|
pulls.merge_conflict_summary = Error Message
|
||||||
pulls.rebase_conflict = Merge Failed: There was a conflict whilst rebasing commit: %[1]s. Hint: Try a different strategy
|
pulls.rebase_conflict = Merge Failed: There was a conflict whilst rebasing commit: %[1]s. Hint: Try a different strategy
|
||||||
pulls.rebase_conflict_summary = Error Message
|
pulls.rebase_conflict_summary = Error Message
|
||||||
; </summary><code>%[2]s<br>%[3]s</code></details>
|
|
||||||
pulls.unrelated_histories = Merge Failed: The merge head and base do not share a common history. Hint: Try a different strategy
|
pulls.unrelated_histories = Merge Failed: The merge head and base do not share a common history. Hint: Try a different strategy
|
||||||
pulls.merge_out_of_date = Merge Failed: Whilst generating the merge, the base was updated. Hint: Try again.
|
pulls.merge_out_of_date = Merge Failed: Whilst generating the merge, the base was updated. Hint: Try again.
|
||||||
pulls.head_out_of_date = Merge Failed: Whilst generating the merge, the head was updated. Hint: Try again.
|
pulls.head_out_of_date = Merge Failed: Whilst generating the merge, the head was updated. Hint: Try again.
|
||||||
|
@ -1935,7 +1934,7 @@ settings.trust_model.collaborator.long = Collaborator: Trust signatures by colla
|
||||||
settings.trust_model.collaborator.desc = Valid signatures by collaborators of this repository will be marked "trusted" - (whether they match the committer or not). Otherwise, valid signatures will be marked "untrusted" if the signature matches the committer and "unmatched" if not.
|
settings.trust_model.collaborator.desc = Valid signatures by collaborators of this repository will be marked "trusted" - (whether they match the committer or not). Otherwise, valid signatures will be marked "untrusted" if the signature matches the committer and "unmatched" if not.
|
||||||
settings.trust_model.committer = Committer
|
settings.trust_model.committer = Committer
|
||||||
settings.trust_model.committer.long = Committer: Trust signatures that match committers (This matches GitHub and will force Gitea signed commits to have Gitea as the committer)
|
settings.trust_model.committer.long = Committer: Trust signatures that match committers (This matches GitHub and will force Gitea signed commits to have Gitea as the committer)
|
||||||
settings.trust_model.committer.desc = Valid signatures will only be marked "trusted" if they match the committer, otherwise they will be marked "unmatched". This will force Gitea to be the committer on signed commits with the actual committer marked as Co-authored-by: and Co-committed-by: trailer in the commit. The default Gitea key must match a User in the database.
|
settings.trust_model.committer.desc = Valid signatures will only be marked "trusted" if they match the committer, otherwise they will be marked "unmatched". This forces Gitea to be the committer on signed commits with the actual committer marked as Co-authored-by: and Co-committed-by: trailer in the commit. The default Gitea key must match a User in the database.
|
||||||
settings.trust_model.collaboratorcommitter = Collaborator+Committer
|
settings.trust_model.collaboratorcommitter = Collaborator+Committer
|
||||||
settings.trust_model.collaboratorcommitter.long = Collaborator+Committer: Trust signatures by collaborators which match the committer
|
settings.trust_model.collaboratorcommitter.long = Collaborator+Committer: Trust signatures by collaborators which match the committer
|
||||||
settings.trust_model.collaboratorcommitter.desc = Valid signatures by collaborators of this repository will be marked "trusted" if they match the committer. Otherwise, valid signatures will be marked "untrusted" if the signature matches the committer and "unmatched" otherwise. This will force Gitea to be marked as the committer on signed commits with the actual committer marked as Co-Authored-By: and Co-Committed-By: trailer in the commit. The default Gitea key must match a User in the database.
|
settings.trust_model.collaboratorcommitter.desc = Valid signatures by collaborators of this repository will be marked "trusted" if they match the committer. Otherwise, valid signatures will be marked "untrusted" if the signature matches the committer and "unmatched" otherwise. This will force Gitea to be marked as the committer on signed commits with the actual committer marked as Co-Authored-By: and Co-Committed-By: trailer in the commit. The default Gitea key must match a User in the database.
|
||||||
|
@ -2135,10 +2134,10 @@ settings.dismiss_stale_approvals_desc = When new commits that change the content
|
||||||
settings.require_signed_commits = Require Signed Commits
|
settings.require_signed_commits = Require Signed Commits
|
||||||
settings.require_signed_commits_desc = Reject pushes to this branch if they are unsigned or unverifiable.
|
settings.require_signed_commits_desc = Reject pushes to this branch if they are unsigned or unverifiable.
|
||||||
settings.protect_branch_name_pattern = Protected Branch Name Pattern
|
settings.protect_branch_name_pattern = Protected Branch Name Pattern
|
||||||
settings.protect_protected_file_patterns = Protected file patterns (separated using semicolon '\;'):
|
settings.protect_protected_file_patterns = `Protected file patterns (separated using semicolon ';'):`
|
||||||
settings.protect_protected_file_patterns_desc = Protected files that are not allowed to be changed directly even if user has rights to add, edit, or delete files in this branch. Multiple patterns can be separated using semicolon ('\;'). See <a href="https://pkg.go.dev/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a> documentation for pattern syntax. Examples: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>.
|
settings.protect_protected_file_patterns_desc = `Protected files are not allowed to be changed directly even if user has rights to add, edit, or delete files in this branch. Multiple patterns can be separated using semicolon (';'). See <a href="https://pkg.go.dev/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a> documentation for pattern syntax. Examples: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>.`
|
||||||
settings.protect_unprotected_file_patterns = Unprotected file patterns (separated using semicolon '\;'):
|
settings.protect_unprotected_file_patterns = `Unprotected file patterns (separated using semicolon ';'):`
|
||||||
settings.protect_unprotected_file_patterns_desc = Unprotected files that are allowed to be changed directly if user has write access, bypassing push restriction. Multiple patterns can be separated using semicolon ('\;'). See <a href="https://pkg.go.dev/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a> documentation for pattern syntax. Examples: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>.
|
settings.protect_unprotected_file_patterns_desc = `Unprotected files that are allowed to be changed directly if user has write access, bypassing push restriction. Multiple patterns can be separated using semicolon (';'). See <a href="https://pkg.go.dev/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a> documentation for pattern syntax. Examples: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>.`
|
||||||
settings.add_protected_branch = Enable protection
|
settings.add_protected_branch = Enable protection
|
||||||
settings.delete_protected_branch = Disable protection
|
settings.delete_protected_branch = Disable protection
|
||||||
settings.update_protect_branch_success = Branch protection for rule '%s' has been updated.
|
settings.update_protect_branch_success = Branch protection for rule '%s' has been updated.
|
||||||
|
@ -2481,7 +2480,7 @@ teams.remove_all_repos_title = Remove all team repositories
|
||||||
teams.remove_all_repos_desc = This will remove all repositories from the team.
|
teams.remove_all_repos_desc = This will remove all repositories from the team.
|
||||||
teams.add_all_repos_title = Add all repositories
|
teams.add_all_repos_title = Add all repositories
|
||||||
teams.add_all_repos_desc = This will add all the organization's repositories to the team.
|
teams.add_all_repos_desc = This will add all the organization's repositories to the team.
|
||||||
teams.add_nonexistent_repo = "The repository you're trying to add does not exist; please create it first."
|
teams.add_nonexistent_repo = "The repository you're trying to add doesn't exist, please create it first."
|
||||||
teams.add_duplicate_users = User is already a team member.
|
teams.add_duplicate_users = User is already a team member.
|
||||||
teams.repos.none = No repositories could be accessed by this team.
|
teams.repos.none = No repositories could be accessed by this team.
|
||||||
teams.members.none = No members on this team.
|
teams.members.none = No members on this team.
|
||||||
|
@ -2511,7 +2510,7 @@ first_page = First
|
||||||
last_page = Last
|
last_page = Last
|
||||||
total = Total: %d
|
total = Total: %d
|
||||||
|
|
||||||
dashboard.new_version_hint = Gitea %s is now available, you are running %s. Check the <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">blog</a> for more details.
|
dashboard.new_version_hint = Gitea %s is now available, you are running %s. Check <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">the blog</a> for more details.
|
||||||
dashboard.statistic = Summary
|
dashboard.statistic = Summary
|
||||||
dashboard.operations = Maintenance Operations
|
dashboard.operations = Maintenance Operations
|
||||||
dashboard.system_status = System Status
|
dashboard.system_status = System Status
|
||||||
|
@ -2631,7 +2630,7 @@ users.still_own_repo = This user still owns one or more repositories. Delete or
|
||||||
users.still_has_org = This user is a member of an organization. Remove the user from any organizations first.
|
users.still_has_org = This user is a member of an organization. Remove the user from any organizations first.
|
||||||
users.purge = Purge User
|
users.purge = Purge User
|
||||||
users.purge_help = Forcibly delete user and any repositories, organizations, and packages owned by the user. All comments will be deleted too.
|
users.purge_help = Forcibly delete user and any repositories, organizations, and packages owned by the user. All comments will be deleted too.
|
||||||
users.still_own_packages = This user still owns one or more packages. Delete these packages first.
|
users.still_own_packages = This user still owns one or more packages, delete these packages first.
|
||||||
users.deletion_success = The user account has been deleted.
|
users.deletion_success = The user account has been deleted.
|
||||||
users.reset_2fa = Reset 2FA
|
users.reset_2fa = Reset 2FA
|
||||||
users.list_status_filter.menu_text = Filter
|
users.list_status_filter.menu_text = Filter
|
||||||
|
|
Loading…
Reference in a new issue