Skip to content

Commit

Permalink
Merge pull request #139 from maximilien/feat/add-trans
Browse files Browse the repository at this point in the history
chore: add english translation to source code
  • Loading branch information
maximilien authored Jul 19, 2024
2 parents aedab4e + 84c2ee7 commit 8e4b0ee
Show file tree
Hide file tree
Showing 45 changed files with 2,098 additions and 291 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,6 @@ jobs:
run: |
export GOPATH=$(go env GOPATH)/bin
./bin/test
- name: Validate
run: ./bin/validate
46 changes: 46 additions & 0 deletions bin/validate
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/bin/env bash

# Copyright © 2015-2023 The Knative Authors
# 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.

set -e

echo -e "\nUpdate (Re)generated translation files..."

PROJ_DIR=$(cd $(dirname $(dirname $0)) && pwd)
if [[ -z $(command -v go-bindata) ]]; then
echo -e "\nInstalling go-bindata..."
# install outside of GO PATH
pushd /tmp >/dev/null
go install -a -v github.com/go-bindata/go-bindata/...@latest
popd > /dev/null
fi

pushd $PROJ_DIR >/dev/null
go-bindata -pkg resources -o resources -o i18n4go/resources/i18n_resources.go -nocompress i18n4go/i18n/resources/*.json
echo -e "\nCompleted."

popd >/dev/null

echo -e "\nVerify translation messages"

if [[ ! -f $PROJ_DIR/out/i18n4go ]]; then
echo -e "\nMissing built bui18n4go binary..."
exit 1
fi

pushd i18n4go >/dev/null
$PROJ_DIR/out/i18n4go checkup -q i18n -v
popd

echo -e "\nComplete."
33 changes: 17 additions & 16 deletions i18n4go/cmds/checkup.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/spf13/cobra"

"github.com/maximilien/i18n4go/i18n4go/common"
"github.com/maximilien/i18n4go/i18n4go/i18n"
)

type Checkup struct {
Expand All @@ -51,15 +52,15 @@ func NewCheckup(options *common.Options) *Checkup {
func NewCheckupCommand(options *common.Options) *cobra.Command {
checkupCmd := &cobra.Command{
Use: "checkup",
Short: "Checks the transated files",
Short: i18n.T("Checks the transated files"),
RunE: func(cmd *cobra.Command, args []string) error {
return NewCheckup(options).Run()
},
}

checkupCmd.Flags().StringVarP(&options.QualifierFlag, "qualifier", "q", "", "[optional] the qualifier string that is used when using the T(...) function, default to nothing but could be set to `i18n` so that all calls would be: i18n.T(...)")
checkupCmd.Flags().StringVarP(&options.QualifierFlag, "qualifier", "q", "", i18n.T("[optional] the qualifier string that is used when using the i18n.T(...) function, default to nothing but could be set to `i18n` so that all calls would be: i18n.T(...)"))
// TODO: Optional flags shouldn't have set defaults. We should look into removing the default
checkupCmd.Flags().StringVar(&options.IgnoreRegexpFlag, "ignore-regexp", ".*test.*", "recursively extract strings from all files in the same directory as filename or dirName")
checkupCmd.Flags().StringVar(&options.IgnoreRegexpFlag, "ignore-regexp", ".*test.*", i18n.T("recursively extract strings from all files in the same directory as filename or dirName"))
return checkupCmd
}

Expand Down Expand Up @@ -88,26 +89,26 @@ func (cu *Checkup) Run() error {
sourceStrings, err := cu.findSourceStrings()

if err != nil {
cu.Println(fmt.Sprintf("Couldn't find any source strings: %s", err.Error()))
cu.Println(i18n.T("Couldn't find any source strings: {{.Arg0}}", map[string]interface{}{"Arg0": err.Error()}))
return err
}

locales := findTranslationFiles(".", cu.IgnoreRegexp, false)

englishFiles := locales["en_US"]
if englishFiles == nil {
cu.Println("Could not find an i18n file for locale: en_US")
return errors.New("Could not find an i18n file for locale: en_US")
cu.Println(i18n.T("Could not find an i18n file for locale: en_US"))
return errors.New(i18n.T("Could not find an i18n file for locale: en_US"))
}

englishStrings, err := cu.findI18nStrings(englishFiles)

if err != nil {
cu.Println(fmt.Sprintf("Couldn't find the english strings: %s", err.Error()))
cu.Println(i18n.T("Couldn't find the english strings: {{.Arg0}}", map[string]interface{}{"Arg0": err.Error()}))
return err
}

err = cu.diffStrings("the code", "en_US", sourceStrings, englishStrings)
err = cu.diffStrings(i18n.T("the code"), "en_US", sourceStrings, englishStrings)

for locale, i18nFiles := range locales {
if locale == "en_US" {
Expand All @@ -117,15 +118,15 @@ func (cu *Checkup) Run() error {
translatedStrings, err := cu.findI18nStrings(i18nFiles)

if err != nil {
cu.Println(fmt.Sprintf("Couldn't get the strings from %s: %s", locale, err.Error()))
cu.Println(i18n.T("Couldn't get the strings from {{.Arg0}}: {{.Arg1}}", map[string]interface{}{"Arg0": locale, "Arg1": err.Error()}))
return err
}

err = cu.diffStrings("en_US", locale, englishStrings, translatedStrings)
}

if err == nil {
cu.Printf("OK")
cu.Printf(i18n.T("OK"))
}

return err
Expand Down Expand Up @@ -269,7 +270,7 @@ func (cu *Checkup) findSourceStrings() (sourceStrings map[string]string, err err
for _, file := range files {
fileStrings, err := cu.inspectFile(file)
if err != nil {
cu.Println("Error when inspecting go file: ", file)
cu.Println(i18n.T("Error when inspecting go file: "), file)
return sourceStrings, err
}

Expand All @@ -293,7 +294,7 @@ func getI18nFile(locale, dir string) (filePath string) {
name := fileInfo.Name()

// assume the file path is a json file and the path contains the locale
if strings.HasSuffix(name, ".json") && strings.Contains(name, fmt.Sprintf("%s.", locale)) {
if strings.HasSuffix(name, ".json") && strings.Contains(name, fmt.Sprintf("{{.Arg0}}.", map[string]interface{}{"Arg0": locale})) {
filePath = filepath.Join(dir, fileInfo.Name())
break
}
Expand Down Expand Up @@ -379,15 +380,15 @@ func (cu *Checkup) findI18nStrings(i18nFiles []string) (i18nStrings map[string]s
func (cu *Checkup) diffStrings(sourceNameOne, sourceNameTwo string, stringsOne, stringsTwo map[string]string) (err error) {
for key, _ := range stringsOne {
if stringsTwo[key] == "" {
cu.Printf("\"%s\" exists in %s, but not in %s\n", key, sourceNameOne, sourceNameTwo)
err = errors.New("Strings don't match")
cu.Printf(i18n.T("\"{{.Arg0}}\" exists in {{.Arg1}}, but not in {{.Arg2}}\n", map[string]interface{}{"Arg0": key, "Arg1": sourceNameOne, "Arg2": sourceNameTwo}))
err = errors.New(i18n.T("Strings don't match"))
}
}

for key, _ := range stringsTwo {
if stringsOne[key] == "" {
cu.Printf("\"%s\" exists in %s, but not in %s\n", key, sourceNameTwo, sourceNameOne)
err = errors.New("Strings don't match")
cu.Printf(i18n.T("\"{{.Arg0}}\" exists in {{.Arg1}}, but not in {{.Arg2}}\n", map[string]interface{}{"Arg0": key, "Arg1": sourceNameTwo, "Arg2": sourceNameOne}))
err = errors.New(i18n.T("Strings don't match"))
}
}

Expand Down
51 changes: 26 additions & 25 deletions i18n4go/cmds/create_translations.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/spf13/cobra"

"github.com/maximilien/i18n4go/i18n4go/common"
"github.com/maximilien/i18n4go/i18n4go/i18n"
)

type createTranslations struct {
Expand Down Expand Up @@ -74,19 +75,19 @@ func NewCreateTranslations(options *common.Options) *createTranslations {
func NewCreateTranslationsCommand(options *common.Options) *cobra.Command {
createTranslationsCmd := &cobra.Command{
Use: "create-translations",
Short: "Creates the transation files",
Short: i18n.T("Creates the transation files"),
RunE: func(cmd *cobra.Command, args []string) error {
return NewCreateTranslations(options).Run()
},
}

// TODO: --google-translate-api-key is too long of an optional flag
// might want to shorten it or add an alias for usability
createTranslationsCmd.Flags().StringVar(&options.GoogleTranslateApiKeyFlag, "google-translate-api-key", "", "[optional] your public Google Translate API key which is used to generate translations (charge is applicable)")
createTranslationsCmd.Flags().StringVarP(&options.SourceLanguageFlag, "source-language", "s", "en", "the source language of the file, typically also part of the file name, e.g., \"en_US\"")
createTranslationsCmd.Flags().StringVarP(&options.FilenameFlag, "file", "f", "", "the source translation file")
createTranslationsCmd.Flags().StringVarP(&options.LanguagesFlag, "languages", "l", "", "a comma separated list of valid languages with optional territory, e.g., \"en, en_US, fr_FR, es\"")
createTranslationsCmd.Flags().StringVarP(&options.OutputDirFlag, "output", "o", "", "the output directory where the newly created translation files will be placed")
createTranslationsCmd.Flags().StringVar(&options.GoogleTranslateApiKeyFlag, "google-translate-api-key", "", i18n.T("[optional] your public Google Translate API key which is used to generate translations (charge is applicable)"))
createTranslationsCmd.Flags().StringVarP(&options.SourceLanguageFlag, "source-language", "s", "en", i18n.T("the source language of the file, typically also part of the file name, e.g., \"en_US\""))
createTranslationsCmd.Flags().StringVarP(&options.FilenameFlag, "file", "f", "", i18n.T("the source translation file"))
createTranslationsCmd.Flags().StringVarP(&options.LanguagesFlag, "languages", "l", "", i18n.T("a comma separated list of valid languages with optional territory, e.g., \"en, en_US, fr_FR, es\""))
createTranslationsCmd.Flags().StringVarP(&options.OutputDirFlag, "output", "o", "", i18n.T("the output directory where the newly created translation files will be placed"))

return createTranslationsCmd

Expand All @@ -113,24 +114,24 @@ func (ct *createTranslations) Printf(msg string, a ...interface{}) (int, error)
}

func (ct *createTranslations) Run() error {
ct.Println("i18n4go: creating translation files for:", ct.Filename)
ct.Println(i18n.T("i18n4go: creating translation files for:"), ct.Filename)
ct.Println()

for _, language := range ct.Languages {
ct.Println("i18n4go: creating translation file copy for language:", language)
ct.Println(i18n.T("i18n4go: creating translation file copy for language:"), language)

if ct.options.GoogleTranslateApiKeyFlag != "" {
destFilename, err := ct.createTranslationFileWithGoogleTranslate(language)
if err != nil {
return fmt.Errorf("i18n4go: could not create translation file for language: %s with Google Translate", language)
return fmt.Errorf(i18n.T("i18n4go: could not create translation file for language: {{.Arg0}} with Google Translate", map[string]interface{}{"Arg0": language}))
}
ct.Println("i18n4go: created translation file with Google Translate:", destFilename)
ct.Println(i18n.T("i18n4go: created translation file with Google Translate:"), destFilename)
} else {
destFilename, err := ct.createTranslationFile(ct.Filename, language)
if err != nil {
return fmt.Errorf("i18n4go: could not create default translation file for language: %s\nerr:%s", language, err.Error())
return fmt.Errorf(i18n.T("i18n4go: could not create default translation file for language: {{.Arg0}}\nerr:{{.Arg1}}", map[string]interface{}{"Arg0": language, "Arg1": err.Error()}))
}
ct.Println("i18n4go: created default translation file:", destFilename)
ct.Println(i18n.T("i18n4go: created default translation file:"), destFilename)
}
}

Expand All @@ -148,27 +149,27 @@ func (ct *createTranslations) createTranslationFileWithGoogleTranslate(language
err = common.CreateOutputDirsIfNeeded(ct.OutputDirname)
if err != nil {
ct.Println(err)
return "", fmt.Errorf("i18n4go: could not create output directory: %s", ct.OutputDirname)
return "", fmt.Errorf(i18n.T("i18n4go: could not create output directory: {{.Arg0}}", map[string]interface{}{"Arg0": ct.OutputDirname}))
}

destFilename := filepath.Join(ct.OutputDirname, strings.Replace(fileName, ct.options.SourceLanguageFlag, language, -1))

i18nStringInfos, err := common.LoadI18nStringInfos(ct.Filename)
if err != nil {
ct.Println(err)
return "", fmt.Errorf("i18n4go: could not load i18n strings from file: %s", ct.Filename)
return "", fmt.Errorf(i18n.T("i18n4go: could not load i18n strings from file: {{.Arg0}}", map[string]interface{}{"Arg0": ct.Filename}))
}

if len(i18nStringInfos) == 0 {
return "", fmt.Errorf("i18n4go: input file: %s is empty", ct.Filename)
return "", fmt.Errorf(i18n.T("i18n4go: input file: {{.Arg0}} is empty", map[string]interface{}{"Arg0": ct.Filename}))
}

ct.Println("i18n4go: attempting to use Google Translate to translate source strings in: ", language)
ct.Println(i18n.T("i18n4go: attempting to use Google Translate to translate source strings in: "), language)
modifiedI18nStringInfos := make([]common.I18nStringInfo, len(i18nStringInfos))
for i, i18nStringInfo := range i18nStringInfos {
translation, _, err := ct.googleTranslate(i18nStringInfo.Translation, language)
if err != nil {
ct.Println("i18n4go: error invoking Google Translate for string:", i18nStringInfo.Translation)
ct.Println(i18n.T("i18n4go: error invoking Google Translate for string:"), i18nStringInfo.Translation)
} else {
modifiedI18nStringInfos[i] = common.I18nStringInfo{ID: i18nStringInfo.ID, Translation: translation}
}
Expand All @@ -177,15 +178,15 @@ func (ct *createTranslations) createTranslationFileWithGoogleTranslate(language
err = common.SaveI18nStringInfos(ct, ct.Options(), modifiedI18nStringInfos, destFilename)
if err != nil {
ct.Println(err)
return "", fmt.Errorf("i18n4go: could not save Google Translate i18n strings to file: %s", destFilename)
return "", fmt.Errorf(i18n.T("i18n4go: could not save Google Translate i18n strings to file: {{.Arg0}}", map[string]interface{}{"Arg0": destFilename}))
}

if ct.options.PoFlag {
poFilename := destFilename[:len(destFilename)-len(".json")] + ".po"
err = common.SaveI18nStringsInPo(ct, ct.Options(), modifiedI18nStringInfos, poFilename)
if err != nil {
ct.Println(err)
return "", fmt.Errorf("i18n4go: could not save PO file: %s", poFilename)
return "", fmt.Errorf(i18n.T("i18n4go: could not save PO file: {{.Arg0}}", map[string]interface{}{"Arg0": poFilename}))
}
}

Expand All @@ -203,15 +204,15 @@ func (ct *createTranslations) createTranslationFile(sourceFilename string, langu
i18nStringInfos, err := common.LoadI18nStringInfos(sourceFilename)
if err != nil {
ct.Println(err)
return "", fmt.Errorf("i18n4go: could not load i18n strings from file: %s", sourceFilename)
return "", fmt.Errorf(i18n.T("i18n4go: could not load i18n strings from file: {{.Arg0}}", map[string]interface{}{"Arg0": sourceFilename}))
}

if len(i18nStringInfos) == 0 {
return "", fmt.Errorf("i18n4go: input file: %s is empty", sourceFilename)
return "", fmt.Errorf(i18n.T("i18n4go: input file: {{.Arg0}} is empty", map[string]interface{}{"Arg0": sourceFilename}))
}

destFilename := filepath.Join(ct.OutputDirname, strings.Replace(fileName, ct.options.SourceLanguageFlag, language, -1))
ct.Println("i18n4go: creating translation file:", destFilename)
ct.Println(i18n.T("i18n4go: creating translation file:"), destFilename)

return destFilename, common.CopyFileContents(sourceFilename, destFilename)
}
Expand All @@ -222,22 +223,22 @@ func (ct *createTranslations) googleTranslate(translateString string, language s

response, err := http.Get(googleTranslateUrl)
if err != nil {
ct.Println("i18n4go: ERROR invoking Google Translate: ", googleTranslateUrl)
ct.Println(i18n.T("i18n4go: ERROR invoking Google Translate: "), googleTranslateUrl)
return "", "", err
}

defer response.Body.Close()

body, err := ioutil.ReadAll(response.Body)
if err != nil {
ct.Println("i18n4go: ERROR parsing Google Translate response body")
ct.Println(i18n.T("i18n4go: ERROR parsing Google Translate response body"))
return "", "", err
}

var googleTranslateData GoogleTranslateData
err = json.Unmarshal(body, &googleTranslateData)
if err != nil {
ct.Println("i18n4go: ERROR parsing Google Translate response body")
ct.Println(i18n.T("i18n4go: ERROR parsing Google Translate response body"))
return "", "", err
}

Expand Down
Loading

0 comments on commit 8e4b0ee

Please sign in to comment.