loading up the forgejo repo on tangled to test page performance
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Clarify Gitea/Crowdin locale behaviors, add tests for LocaleStore, fix some strings with semicolons (#23819)

Follow #23633 and #23240

Close #23814

Now we almost have a complete test set for Gitea's LocalStore.

This PR is still a quick fix for the legacy locale system (see the
TODOs), to resolve the problems fundamentally, it needs more work in the
future.

authored by

wxiaoguang and committed by
GitHub
288c2e8c d5feb10a

+61 -14
+3 -10
build/update-locales.sh
··· 17 17 18 18 mv ./options/locale/locale_en-US.ini ./options/ 19 19 20 - # the "ini" library for locale has many quirks 21 - # * `a="xx"` gets `xx` (no quote) 22 - # * `a=x\"y` gets `x\"y` (no unescaping) 23 - # * `a="x\"y"` gets `"x\"y"` (no unescaping, the quotes are still there) 24 - # * `a='x\"y'` gets `x\"y` (no unescaping, no quote) 25 - # * `a="foo` gets `"foo` (although the quote is not closed) 26 - # * 'a=`foo`' works like single-quote 27 - # crowdin needs the strings to be quoted correctly and doesn't like incomplete quotes 28 - # crowdin always outputs quoted strings if there are quotes in the strings. 20 + # the "ini" library for locale has many quirks, its behavior is different from Crowdin. 21 + # see i18n_test.go for more details 29 22 30 - # this script helps to unquote the crowdin outputs for the quirky ini library 23 + # this script helps to unquote the Crowdin outputs for the quirky ini library 31 24 # * find all `key="...\"..."` lines 32 25 # * remove the leading quote 33 26 # * remove the trailing quote
+54
modules/translation/i18n/i18n_test.go
··· 4 4 package i18n 5 5 6 6 import ( 7 + "strings" 7 8 "testing" 8 9 9 10 "github.com/stretchr/testify/assert" ··· 75 76 assert.Equal(t, "21", ls.Tr("lang1", "b")) 76 77 assert.Equal(t, "22", ls.Tr("lang1", "c")) 77 78 } 79 + 80 + func TestLocaleStoreQuirks(t *testing.T) { 81 + const nl = "\n" 82 + q := func(q1, s string, q2 ...string) string { 83 + return q1 + s + strings.Join(q2, "") 84 + } 85 + testDataList := []struct { 86 + in string 87 + out string 88 + hint string 89 + }{ 90 + {` xx`, `xx`, "simple, no quote"}, 91 + {`" xx"`, ` xx`, "simple, double-quote"}, 92 + {`' xx'`, ` xx`, "simple, single-quote"}, 93 + {"` xx`", ` xx`, "simple, back-quote"}, 94 + 95 + {`x\"y`, `x\"y`, "no unescape, simple"}, 96 + {q(`"`, `x\"y`, `"`), `"x\"y"`, "unescape, double-quote"}, 97 + {q(`'`, `x\"y`, `'`), `x\"y`, "no unescape, single-quote"}, 98 + {q("`", `x\"y`, "`"), `x\"y`, "no unescape, back-quote"}, 99 + 100 + {q(`"`, `x\"y`) + nl + "b=", `"x\"y`, "half open, double-quote"}, 101 + {q(`'`, `x\"y`) + nl + "b=", `'x\"y`, "half open, single-quote"}, 102 + {q("`", `x\"y`) + nl + "b=`", `x\"y` + nl + "b=", "half open, back-quote, multi-line"}, 103 + 104 + {`x ; y`, `x ; y`, "inline comment (;)"}, 105 + {`x # y`, `x # y`, "inline comment (#)"}, 106 + {`x \; y`, `x ; y`, `inline comment (\;)`}, 107 + {`x \# y`, `x # y`, `inline comment (\#)`}, 108 + } 109 + 110 + for _, testData := range testDataList { 111 + ls := NewLocaleStore() 112 + err := ls.AddLocaleByIni("lang1", "Lang1", []byte("a="+testData.in), nil) 113 + assert.NoError(t, err, testData.hint) 114 + assert.Equal(t, testData.out, ls.Tr("lang1", "a"), testData.hint) 115 + assert.NoError(t, ls.Close()) 116 + } 117 + 118 + // TODO: Crowdin needs the strings to be quoted correctly and doesn't like incomplete quotes 119 + // and Crowdin always outputs quoted strings if there are quotes in the strings. 120 + // So, Gitea's `key="quoted" unquoted` content shouldn't be used on Crowdin directly, 121 + // it should be converted to `key="\"quoted\" unquoted"` first. 122 + // TODO: We can not use UnescapeValueDoubleQuotes=true, because there are a lot of back-quotes in en-US.ini, 123 + // then Crowdin will output: 124 + // > key = "`x \" y`" 125 + // Then Gitea will read a string with back-quotes, which is incorrect. 126 + // TODO: Crowdin might generate multi-line strings, quoted by double-quote, it's not supported by LocaleStore 127 + // LocaleStore uses back-quote for multi-line strings, it's not supported by Crowdin. 128 + // TODO: Crowdin doesn't support back-quote as string quoter, it mainly uses double-quote 129 + // so, the following line will be parsed as: value="`first", comment="second`" on Crowdin 130 + // > a = `first; second` 131 + }
+4 -4
options/locale/locale_en-US.ini
··· 2140 2140 settings.require_signed_commits = Require Signed Commits 2141 2141 settings.require_signed_commits_desc = Reject pushes to this branch if they are unsigned or unverifiable. 2142 2142 settings.protect_branch_name_pattern = Protected Branch Name Pattern 2143 - settings.protect_protected_file_patterns = `Protected file patterns (separated using semicolon ';'):` 2144 - 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>.` 2145 - settings.protect_unprotected_file_patterns = `Unprotected file patterns (separated using semicolon ';'):` 2146 - 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>.` 2143 + settings.protect_protected_file_patterns = "Protected file patterns (separated using semicolon ';'):" 2144 + 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>." 2145 + settings.protect_unprotected_file_patterns = "Unprotected file patterns (separated using semicolon ';'):" 2146 + 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>." 2147 2147 settings.add_protected_branch = Enable protection 2148 2148 settings.delete_protected_branch = Disable protection 2149 2149 settings.update_protect_branch_success = Branch protection for rule '%s' has been updated.