Skip to content

Commit

Permalink
feat: add i18n for frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
HeartLinked committed May 29, 2024
1 parent d5735db commit 6bea545
Show file tree
Hide file tree
Showing 14 changed files with 1,065 additions and 239 deletions.
97 changes: 97 additions & 0 deletions i18n/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package i18n

import (
"fmt"
"os"
"path/filepath"
"regexp"
"strings"

"github.com/casbin/caswaf/util"
)

type I18nData map[string]map[string]string

var reI18n *regexp.Regexp

func init() {
reI18n, _ = regexp.Compile("i18next.t\\(\"(.*?)\"\\)")
}

func getAllI18nStrings(fileContent string) []string {
res := []string{}

matches := reI18n.FindAllStringSubmatch(fileContent, -1)
if matches == nil {
return res
}

for _, match := range matches {
res = append(res, match[1])
}
return res
}

func getAllJsFilePaths() []string {
path := "../web/src"

res := []string{}
err := filepath.Walk(path,
func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}

if !strings.HasSuffix(info.Name(), ".js") {
return nil
}

res = append(res, path)
fmt.Println(path, info.Name())
return nil
})
if err != nil {
panic(err)
}

return res
}

func parseToData() *I18nData {
allWords := []string{}
paths := getAllJsFilePaths()
for _, path := range paths {
fileContent := util.ReadStringFromPath(path)
words := getAllI18nStrings(fileContent)
allWords = append(allWords, words...)
}
fmt.Printf("%v\n", allWords)

data := I18nData{}
for _, word := range allWords {
tokens := strings.Split(word, ":")
namespace := tokens[0]
key := tokens[1]

if _, ok := data[namespace]; !ok {
data[namespace] = map[string]string{}
}
data[namespace][key] = key
}

return &data
}
42 changes: 42 additions & 0 deletions i18n/generate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build !skipCi
// +build !skipCi

package i18n

import "testing"

func applyToOtherLanguage(dataEn *I18nData, lang string) {
dataOther := readI18nFile(lang)
println(dataOther)

applyData(dataEn, dataOther)
writeI18nFile(lang, dataEn)
}

func TestGenerateI18nStrings(t *testing.T) {
dataEn := parseToData()
writeI18nFile("en", dataEn)

applyToOtherLanguage(dataEn, "zh")
applyToOtherLanguage(dataEn, "fr")
applyToOtherLanguage(dataEn, "de")
applyToOtherLanguage(dataEn, "id")
applyToOtherLanguage(dataEn, "ja")
applyToOtherLanguage(dataEn, "ko")
applyToOtherLanguage(dataEn, "ru")
applyToOtherLanguage(dataEn, "es")
}
63 changes: 63 additions & 0 deletions i18n/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package i18n

import (
"fmt"
"strings"

"github.com/casbin/caswaf/util"
)

func getI18nFilePath(language string) string {
return fmt.Sprintf("../web/src/locales/%s/data.json", language)
}

func readI18nFile(language string) *I18nData {
s := util.ReadStringFromPath(getI18nFilePath(language))

data := &I18nData{}
err := util.JsonToStruct(s, data)
if err != nil {
panic(err)
}
return data
}

func writeI18nFile(language string, data *I18nData) {
s := util.StructToJson(data)
s = strings.ReplaceAll(s, "\\\\\"", "\"")
println(s)

util.WriteStringToPath(s, getI18nFilePath(language))
}

func applyData(data1 *I18nData, data2 *I18nData) {
for namespace, pairs2 := range *data2 {
if _, ok := (*data1)[namespace]; !ok {
continue
}

pairs1 := (*data1)[namespace]

for key, value := range pairs2 {
if _, ok := pairs1[key]; !ok {
continue
}

pairs1[key] = value
}
}
}
2 changes: 1 addition & 1 deletion web/src/SiteListPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ class SiteListPage extends BaseListPage {
},
},
{
title: i18next.t("site: Enable WAF"),
title: i18next.t("site:Enable WAF"),
dataIndex: "enableWaf",
key: "enableWaf",
width: "120px",
Expand Down
36 changes: 36 additions & 0 deletions web/src/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,28 @@
import i18n from "i18next";
import zh from "./locales/zh/data.json";
import en from "./locales/en/data.json";
import de from "./locales/de/data.json";
import es from "./locales/es/data.json";
import fr from "./locales/fr/data.json";
import id from "./locales/id/data.json";
import ja from "./locales/ja/data.json";
import ko from "./locales/ko/data.json";
import ru from "./locales/ru/data.json";

import * as Conf from "./Conf";
import * as Setting from "./Setting";
import {initReactI18next} from "react-i18next";

const resources = {
en: en,
zh: zh,
de: de,
es: es,
fr: fr,
id: id,
ja: ja,
ko: ko,
ru: ru,
};

function initLanguage() {
Expand All @@ -44,6 +59,27 @@ function initLanguage() {
case "en-US":
language = "en";
break;
case "de":
language = "de";
break;
case "es":
language = "es";
break;
case "fr":
language = "fr";
break;
case "id":
language = "id";
break;
case "ja":
language = "ja";
break;
case "ko":
language = "ko";
break;
case "ru":
language = "ru";
break;
default:
language = Conf.DefaultLanguage;
}
Expand Down
92 changes: 92 additions & 0 deletions web/src/locales/de/data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{
"account": {
"My Account": "My Account",
"Sign In": "Sign In",
"Sign Out": "Sign Out",
"Sign Up": "Sign Up"
},
"cert": {
"Access key": "Access key",
"Access secret": "Access secret",
"Account": "Account",
"Certificate": "Certificate",
"Certificate copied to clipboard successfully": "Certificate copied to clipboard successfully",
"Copy certificate": "Copy certificate",
"Copy private key": "Copy private key",
"Crypto algorithm": "Crypto algorithm",
"Domain expire": "Domain expire",
"Download certificate": "Download certificate",
"Download private key": "Download private key",
"Edit Cert": "Edit Cert",
"Expire time": "Expire time",
"Private key": "Private key",
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
"Provider": "Provider",
"Type": "Type"
},
"general": {
"Action": "Action",
"Add": "Add",
"Back Home": "Back Home",
"Cancel": "Cancel",
"Certs": "Certs",
"Client ip": "Client ip",
"Count": "Count",
"Create time": "Create time",
"Created time": "Created time",
"CreatedTime": "CreatedTime",
"Dashboard": "Dashboard",
"Delete": "Delete",
"Display name": "Display name",
"Edit": "Edit",
"Edit Record": "Edit Record",
"Go to writable demo site?": "Go to writable demo site?",
"Home": "Home",
"Host": "Host",
"ID": "ID",
"IP Address": "IP Address",
"Method": "Method",
"Name": "Name",
"OK": "OK",
"Owner": "Owner",
"Path": "Path",
"Records": "Records",
"Save": "Save",
"Self": "Self",
"Sites": "Sites",
"Sorry, you do not have permission to access this page or logged in status invalid.": "Sorry, you do not have permission to access this page or logged in status invalid.",
"Tag": "Tag",
"This is a read-only demo site!": "This is a read-only demo site!",
"Top 10 IP Addresses": "Top 10 IP Addresses",
"Top 10 User-Agents": "Top 10 User-Agents",
"Total Request Count": "Total Request Count",
"Unique IP Count": "Unique IP Count",
"User agent": "User agent",
"User-Agent": "User-Agent",
"UserAgent": "UserAgent"
},
"site": {
"Casdoor app": "Casdoor app",
"Challenges": "Challenges",
"Domain": "Domain",
"Edit Site": "Edit Site",
"Enable WAF": "Enable WAF",
"Host": "Host",
"Mode": "Mode",
"Need redirect": "Need redirect",
"Node": "Node",
"Nodes": "Nodes",
"Other domains": "Other domains",
"Port": "Port",
"Public IP": "Public IP",
"SSL cert": "SSL cert",
"Status": "Status"
},
"usage": {
"All": "All",
"Day": "Day",
"Hour": "Hour",
"Month": "Month",
"Week": "Week"
}
}
Loading

0 comments on commit 6bea545

Please sign in to comment.