MM-54556: Integrate wip i18n languages (#24308)
* merge languages from https://github.com/mattermost/i18n-wip * allow only supported server locales * Revert "merge languages from https://github.com/mattermost/i18n-wip" This reverts commit 36de545102faffe1e8ba943decdab04bc4f5a55c. We'll let weblate populate these on start instead. * copy fileutils to public/utils --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
a838433263
Коммит
14f784a0cc
@@ -33,6 +33,32 @@ var T TranslateFunc
|
||||
var TDefault TranslateFunc
|
||||
|
||||
var locales = make(map[string]string)
|
||||
|
||||
// supportedLocales is a hard-coded list of locales considered ready for production use. It must
|
||||
// be kept in sync with ../../../../webapp/channels/src/i18n/i18n.jsx.
|
||||
var supportedLocales = []string{
|
||||
"de",
|
||||
"en",
|
||||
"en-AU",
|
||||
"es",
|
||||
"fr",
|
||||
"it",
|
||||
"hu",
|
||||
"nl",
|
||||
"pl",
|
||||
"pt-BR",
|
||||
"ro",
|
||||
"sv",
|
||||
"tr",
|
||||
"bg",
|
||||
"ru",
|
||||
"uk",
|
||||
"fa",
|
||||
"ko",
|
||||
"zh-CN",
|
||||
"zh-TW",
|
||||
"ja",
|
||||
}
|
||||
var defaultServerLocale string
|
||||
var defaultClientLocale string
|
||||
|
||||
@@ -67,7 +93,13 @@ func initTranslationsWithDir(dir string) error {
|
||||
for _, f := range files {
|
||||
if filepath.Ext(f.Name()) == ".json" {
|
||||
filename := f.Name()
|
||||
locales[strings.Split(filename, ".")[0]] = filepath.Join(dir, filename)
|
||||
|
||||
locale := strings.Split(filename, ".")[0]
|
||||
if !isSupportedLocale(locale) {
|
||||
continue
|
||||
}
|
||||
|
||||
locales[locale] = filepath.Join(dir, filename)
|
||||
|
||||
if err := i18n.LoadTranslationFile(filepath.Join(dir, filename)); err != nil {
|
||||
return err
|
||||
@@ -89,8 +121,13 @@ func GetTranslationFuncForDir(dir string) (TranslationFuncByLocal, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
locale := strings.Split(f.Name(), ".")[0]
|
||||
if !isSupportedLocale(locale) {
|
||||
continue
|
||||
}
|
||||
|
||||
filename := f.Name()
|
||||
availableLocals[strings.Split(filename, ".")[0]] = filepath.Join(dir, filename)
|
||||
availableLocals[locale] = filepath.Join(dir, filename)
|
||||
if err := bundle.LoadTranslationFile(filepath.Join(dir, filename)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -116,7 +153,12 @@ func GetTranslationFuncForDir(dir string) (TranslationFuncByLocal, error) {
|
||||
func getTranslationsBySystemLocale() (TranslateFunc, error) {
|
||||
locale := defaultServerLocale
|
||||
if _, ok := locales[locale]; !ok {
|
||||
mlog.Warn("Failed to load system translations for", mlog.String("locale", locale), mlog.String("attempting to fall back to default locale", defaultLocale))
|
||||
mlog.Warn("Failed to load system translations for selected locale, attempting to fall back to default", mlog.String("locale", locale), mlog.String("default_locale", defaultLocale))
|
||||
locale = defaultLocale
|
||||
}
|
||||
|
||||
if !isSupportedLocale(locale) {
|
||||
mlog.Warn("Selected locale is unsupported, attempting to fall back to default", mlog.String("locale", locale), mlog.String("default_locale", defaultLocale))
|
||||
locale = defaultLocale
|
||||
}
|
||||
|
||||
@@ -222,3 +264,13 @@ func IdentityTfunc() TranslateFunc {
|
||||
return translationID
|
||||
}
|
||||
}
|
||||
|
||||
func isSupportedLocale(locale string) bool {
|
||||
for _, supportedLocale := range supportedLocales {
|
||||
if locale == supportedLocale {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -4,12 +4,17 @@
|
||||
package i18n
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/go-i18n/i18n/bundle"
|
||||
"github.com/mattermost/go-i18n/i18n/language"
|
||||
"github.com/mattermost/go-i18n/i18n/translation"
|
||||
"github.com/mattermost/mattermost/server/public/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var htmlTestTranslationBundle *bundle.Bundle
|
||||
@@ -67,3 +72,155 @@ func TestEscapeForHTML(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitTranslationsWithDir(t *testing.T) {
|
||||
i18nDir, found := utils.FindDir("server/i18n")
|
||||
require.True(t, found, "unable to find i18n dir")
|
||||
|
||||
setup := func(t *testing.T, localesToCopy map[string]string) string {
|
||||
tempDir, err := os.MkdirTemp(os.TempDir(), "TestGetTranslationFuncForDir")
|
||||
require.NoError(t, err, "unable to create temporary directory")
|
||||
|
||||
t.Cleanup(func() {
|
||||
err = os.RemoveAll(tempDir)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
for locale, fromLocale := range localesToCopy {
|
||||
err = utils.CopyFile(
|
||||
filepath.Join(i18nDir, fmt.Sprintf("%s.json", fromLocale)),
|
||||
filepath.Join(tempDir, fmt.Sprintf("%s.json", locale)),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
return tempDir
|
||||
}
|
||||
|
||||
t.Run("unsupported locale ignored", func(t *testing.T) {
|
||||
tempDir := setup(t, map[string]string{"en": "en", "fr": "fr", "zz": "en"})
|
||||
|
||||
err := initTranslationsWithDir(tempDir)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, found := locales["zz"]
|
||||
require.False(t, found, "should have ignored unsupported locale")
|
||||
})
|
||||
|
||||
t.Run("malformed, unsupported locale ignored", func(t *testing.T) {
|
||||
tempDir := setup(t, map[string]string{"en": "en", "fr": "fr", "zz": "en"})
|
||||
|
||||
err := os.WriteFile(filepath.Join(tempDir, "xx.json"), []byte{'{'}, os.ModePerm)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = initTranslationsWithDir(tempDir)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, found := locales["xx"]
|
||||
require.False(t, found, "should have ignored malformed, unsupported locale")
|
||||
})
|
||||
|
||||
t.Run("malformed, supported locale causes error", func(t *testing.T) {
|
||||
tempDir := setup(t, map[string]string{"fr": "fr", "zz": "en"})
|
||||
|
||||
err := os.WriteFile(filepath.Join(tempDir, "en.json"), []byte{'{'}, os.ModePerm)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = initTranslationsWithDir(tempDir)
|
||||
require.Error(t, err, "should have failed to load malformed, supported locale")
|
||||
})
|
||||
|
||||
t.Run("known locales loaded ", func(t *testing.T) {
|
||||
tempDir := setup(t, map[string]string{"en": "en", "fr": "fr"})
|
||||
|
||||
err := initTranslationsWithDir(tempDir)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, found := locales["en"]
|
||||
require.True(t, found, "should have found en locale")
|
||||
_, found = locales["fr"]
|
||||
require.True(t, found, "should have found fr locale")
|
||||
_, found = locales["es"]
|
||||
require.False(t, found, "should not have found unloaded es locale")
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetTranslationFuncForDir(t *testing.T) {
|
||||
i18nDir, found := utils.FindDir("server/i18n")
|
||||
require.True(t, found, "unable to find i18n dir")
|
||||
|
||||
setup := func(t *testing.T, localesToCopy map[string]string) string {
|
||||
tempDir, err := os.MkdirTemp(os.TempDir(), "TestGetTranslationFuncForDir")
|
||||
require.NoError(t, err, "unable to create temporary directory")
|
||||
|
||||
t.Cleanup(func() {
|
||||
err = os.RemoveAll(tempDir)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
for locale, fromLocale := range localesToCopy {
|
||||
err = utils.CopyFile(
|
||||
filepath.Join(i18nDir, fmt.Sprintf("%s.json", fromLocale)),
|
||||
filepath.Join(tempDir, fmt.Sprintf("%s.json", locale)),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
return tempDir
|
||||
}
|
||||
|
||||
t.Run("unknown locale falls back to english", func(t *testing.T) {
|
||||
tempDir := setup(t, map[string]string{"en": "en", "fr": "fr", "zz": "en"})
|
||||
|
||||
translationFunc, err := GetTranslationFuncForDir(tempDir)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, translationFunc)
|
||||
|
||||
require.Equal(t, "December", translationFunc("unknown")("December"))
|
||||
})
|
||||
|
||||
t.Run("unsupported locale falls back to english", func(t *testing.T) {
|
||||
tempDir := setup(t, map[string]string{"en": "en", "fr": "fr", "zz": "en"})
|
||||
|
||||
translationFunc, err := GetTranslationFuncForDir(tempDir)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, translationFunc)
|
||||
|
||||
require.Equal(t, "December", translationFunc("zz")("December"))
|
||||
})
|
||||
|
||||
t.Run("malformed, unsupported locale ignored and falls back to english", func(t *testing.T) {
|
||||
tempDir := setup(t, map[string]string{"en": "en", "fr": "fr", "zz": "en"})
|
||||
|
||||
err := os.WriteFile(filepath.Join(tempDir, "xx.json"), []byte{'{'}, os.ModePerm)
|
||||
require.NoError(t, err)
|
||||
|
||||
translationFunc, err := GetTranslationFuncForDir(tempDir)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, translationFunc)
|
||||
|
||||
require.Equal(t, "December", translationFunc("xx")("December"))
|
||||
})
|
||||
|
||||
t.Run("malformed, supported locale causes error", func(t *testing.T) {
|
||||
tempDir := setup(t, map[string]string{"fr": "fr", "zz": "en"})
|
||||
|
||||
err := os.WriteFile(filepath.Join(tempDir, "en.json"), []byte{'{'}, os.ModePerm)
|
||||
require.NoError(t, err)
|
||||
|
||||
translationFunc, err := GetTranslationFuncForDir(tempDir)
|
||||
require.Error(t, err)
|
||||
require.Nil(t, translationFunc)
|
||||
})
|
||||
|
||||
t.Run("known locale matches", func(t *testing.T) {
|
||||
tempDir := setup(t, map[string]string{"en": "en", "fr": "fr"})
|
||||
|
||||
translationFunc, err := GetTranslationFuncForDir(tempDir)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, translationFunc)
|
||||
|
||||
require.Equal(t, "Décembre", translationFunc("fr")("December"))
|
||||
require.Equal(t, "December", translationFunc("en")("December"))
|
||||
})
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user