From 9692bfbbb871e3b5a24f8207f24eda999cac2eb9 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 1 Feb 2026 23:58:26 -0800 Subject: [PATCH 1/2] Migrate backport i18n tool --- CONTRIBUTING.md | 2 +- build/backport-locales.go | 115 -------------------------------------- tools/i18n/backport.go | 85 ++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 116 deletions(-) delete mode 100644 build/backport-locales.go create mode 100644 tools/i18n/backport.go diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 52e4aefb6b729..c64d91a7ebbed 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -183,7 +183,7 @@ Here's how to run the test suite: ## Translation All translation work happens on [Crowdin](https://translate.gitea.com). -The only translation that is maintained in this repository is [the English translation](https://github.com/go-gitea/gitea/blob/main/options/locale/locale_en-US.ini). +The only translation that is maintained in this repository is [the English translation](https://github.com/go-gitea/gitea/blob/main/options/locale/locale_en-US.json). It is synced regularly with Crowdin. \ Other locales on main branch **should not** be updated manually as they will be overwritten with each sync. \ Once a language has reached a **satisfactory percentage** of translated keys (~25%), it will be synced back into this repo and included in the next released version. diff --git a/build/backport-locales.go b/build/backport-locales.go deleted file mode 100644 index d112dd72bd56e..0000000000000 --- a/build/backport-locales.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -//go:build ignore - -package main - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - - "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/setting" -) - -func main() { - if len(os.Args) != 2 { - println("usage: backport-locales ") - println("eg: backport-locales release/v1.19") - os.Exit(1) - } - - mustNoErr := func(err error) { - if err != nil { - panic(err) - } - } - collectInis := func(ref string) map[string]setting.ConfigProvider { - inis := map[string]setting.ConfigProvider{} - 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 := setting.NewConfigProviderForLocale(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"] - brokenWarned := make(container.Set[string]) - 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() - broken := oldStr != "" && strings.Count(oldStr, "%") != strings.Count(newStr, "%") - broken = broken || strings.Contains(oldStr, "\n") || strings.Contains(oldStr, "\n") - if broken { - brokenWarned.Add(secOld.Name() + "." + keyEnUs.Name()) - fmt.Println("----") - fmt.Printf("WARNING: skip broken locale: %s , [%s] %s\n", path, secEnUS.Name(), keyEnUs.Name()) - fmt.Printf("\told: %s\n", strings.ReplaceAll(oldStr, "\n", "\\n")) - fmt.Printf("\tnew: %s\n", strings.ReplaceAll(newStr, "\n", "\\n")) - continue - } - secOld.Key(keyEnUs.Name()).SetValue(newStr) - } - } - } - mustNoErr(iniOld.SaveTo(path)) - } - - fmt.Println("========") - - for path, iniNew := range inisNew { - for _, sec := range iniNew.Sections() { - for _, key := range sec.Keys() { - str := sec.Key(key.Name()).String() - broken := strings.Contains(str, "\n") - broken = broken || strings.HasPrefix(str, "`") != strings.HasSuffix(str, "`") - broken = broken || strings.HasPrefix(str, "\"`") - broken = broken || strings.HasPrefix(str, "`\"") - broken = broken || strings.Count(str, `"`)%2 == 1 - broken = broken || strings.Count(str, "`")%2 == 1 - if broken && !brokenWarned.Contains(sec.Name()+"."+key.Name()) { - fmt.Printf("WARNING: found broken locale: %s , [%s] %s\n", path, sec.Name(), key.Name()) - fmt.Printf("\tstr: %s\n", strings.ReplaceAll(str, "\n", "\\n")) - fmt.Println("----") - } - } - } - } -} diff --git a/tools/i18n/backport.go b/tools/i18n/backport.go new file mode 100644 index 0000000000000..b77d2fab563f2 --- /dev/null +++ b/tools/i18n/backport.go @@ -0,0 +1,85 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +//go:build ignore + +package main + +import ( + "encoding/json" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" +) + +func main() { + if len(os.Args) != 2 { + println("usage: backport-locales ") + println("eg: backport-locales release/v1.19") + os.Exit(1) + } + + mustNoErr := func(err error) { + if err != nil { + panic(err) + } + } + collectJSONs := func(ref string) map[string]map[string]string { + translates := map[string]map[string]string{} // locale -> key -> value + 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(), ".json") { + return nil + } + var translate = make(map[string]string) + data, err := os.ReadFile(path) + if err != nil { + return err + } + if err = json.Unmarshal(data, &translate); err != nil { + return err + } + + translates[filepath.Base(d.Name())] = translate + + fmt.Printf("collecting: %s @ %s\n", path, ref) + return nil + }) + mustNoErr(err) + return translates + } + + // collect new locales from current working directory + translatesNew := collectJSONs("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()) + translatesOld := collectJSONs(os.Args[1]) + + // use old en-US as the base, and copy the new translations to the old locales + enUsOld := translatesOld["locale_en-US.json"] + for path, translateOld := range translatesOld { + jsonNew := translatesNew[path] + if len(jsonNew) == 0 { + continue + } + updated := false + for keyEnUS, _ := range enUsOld { + v, ok := jsonNew[keyEnUS] + if ok && v != translateOld[keyEnUS] { + translateOld[keyEnUS] = v + updated = true + } + } + if updated { + + } + } +} From ba69c562361c34508f790d982598cd0475bfeede Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 15 Feb 2026 23:32:00 -0800 Subject: [PATCH 2/2] Remove translation backport tool at the moment --- tools/i18n/backport.go | 85 ------------------------------------------ 1 file changed, 85 deletions(-) delete mode 100644 tools/i18n/backport.go diff --git a/tools/i18n/backport.go b/tools/i18n/backport.go deleted file mode 100644 index b77d2fab563f2..0000000000000 --- a/tools/i18n/backport.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -//go:build ignore - -package main - -import ( - "encoding/json" - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" -) - -func main() { - if len(os.Args) != 2 { - println("usage: backport-locales ") - println("eg: backport-locales release/v1.19") - os.Exit(1) - } - - mustNoErr := func(err error) { - if err != nil { - panic(err) - } - } - collectJSONs := func(ref string) map[string]map[string]string { - translates := map[string]map[string]string{} // locale -> key -> value - 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(), ".json") { - return nil - } - var translate = make(map[string]string) - data, err := os.ReadFile(path) - if err != nil { - return err - } - if err = json.Unmarshal(data, &translate); err != nil { - return err - } - - translates[filepath.Base(d.Name())] = translate - - fmt.Printf("collecting: %s @ %s\n", path, ref) - return nil - }) - mustNoErr(err) - return translates - } - - // collect new locales from current working directory - translatesNew := collectJSONs("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()) - translatesOld := collectJSONs(os.Args[1]) - - // use old en-US as the base, and copy the new translations to the old locales - enUsOld := translatesOld["locale_en-US.json"] - for path, translateOld := range translatesOld { - jsonNew := translatesNew[path] - if len(jsonNew) == 0 { - continue - } - updated := false - for keyEnUS, _ := range enUsOld { - v, ok := jsonNew[keyEnUS] - if ok && v != translateOld[keyEnUS] { - translateOld[keyEnUS] = v - updated = true - } - } - if updated { - - } - } -}