Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A tool to help to backport locales, changes source strings to fix other broken translations #23633

Merged
merged 10 commits into from
Mar 23, 2023
89 changes: 89 additions & 0 deletions build/backport-locales.go
Original file line number Diff line number Diff line change
@@ -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))
}
}
37 changes: 18 additions & 19 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ openid_signup_popup = Enable OpenID-based user self-registration.
enable_captcha = Enable registration CAPTCHA
enable_captcha_popup = Require a CAPTCHA for user self-registration.
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_title = Administrator Account Settings
admin_name = Administrator Username
Expand Down Expand Up @@ -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'.
password_algorithm = 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 whilst having good characteristics uses a lot of memory and may be inappropriate for small systems.
wxiaoguang marked this conversation as resolved.
Show resolved Hide resolved
enable_update_checker = Enable Update Checker
enable_update_checker_helper = Checks for new version releases periodically by connecting to gitea.io.

Expand Down Expand Up @@ -521,14 +521,14 @@ invalid_ssh_key = Cannot verify your SSH key: %s
invalid_gpg_key = Cannot verify your GPG key: %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.
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

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_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_packages = "This organization still owns one or more packages; delete 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_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_packages = "This organization still owns one or more packages, delete them first."

target_branch_not_exist = Target branch does not exist.

Expand Down Expand Up @@ -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.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.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.failed = Migration failed: %v
migrate.migrate_items_options = Access Token is required to migrate additional items
Expand Down Expand Up @@ -1175,7 +1175,7 @@ commits.commits = Commits
commits.no_commits = No commits in common. '%s' and '%s' have entirely different histories.
commits.nothing_to_compare = These branches are equal.
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-01".
wxiaoguang marked this conversation as resolved.
Show resolved Hide resolved
commits.find = Search
commits.search_all = All Branches
commits.author = Author
Expand Down Expand Up @@ -1635,7 +1635,6 @@ pulls.merge_conflict = Merge Failed: There was a conflict whilst merging. Hint:
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_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.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.
Expand Down Expand Up @@ -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.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.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.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.
Expand Down Expand Up @@ -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_desc = Reject pushes to this branch if they are unsigned or unverifiable.
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_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_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_protected_file_patterns = `Protected file patterns (separated using semicolon ';'):`
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_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.delete_protected_branch = Disable protection
settings.update_protect_branch_success = Branch protection for rule '%s' has been updated.
Expand Down Expand Up @@ -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.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_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.repos.none = No repositories could be accessed by this team.
teams.members.none = No members on this team.
Expand Down Expand Up @@ -2511,7 +2510,7 @@ first_page = First
last_page = Last
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">blog</a> for more details.
wxiaoguang marked this conversation as resolved.
Show resolved Hide resolved
dashboard.statistic = Summary
dashboard.operations = Maintenance Operations
dashboard.system_status = System Status
Expand Down Expand Up @@ -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.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.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.reset_2fa = Reset 2FA
users.list_status_filter.menu_text = Filter
Expand Down