Skip to content

Commit

Permalink
I18n revamp (#747)
Browse files Browse the repository at this point in the history
This moves our i18n support to go-i18n + gotext.

I have marked some strings up for translations, but a more careful and
complete analyze is needed.

pot/po are updated with the new github action, you can see one result of
this merge on https://github.com/didrocks/adsys/pull/11/files. I have
purposefully added and removed some strings in the French translations.

Now, the code can embed translations on desired platforms (like Windows
or dev branch).

UDENG-1097
  • Loading branch information
didrocks authored Jul 31, 2023
2 parents e0cd683 + 1eb09fd commit 76d2053
Show file tree
Hide file tree
Showing 29 changed files with 558 additions and 151 deletions.
32 changes: 9 additions & 23 deletions .github/workflows/auto-updates.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,34 +18,20 @@ jobs:
name: Update po files
runs-on: ubuntu-latest
steps:
- name: Install dependencies
run: |
sudo DEBIAN_FRONTEND=noninteractive apt update
sudo DEBIAN_FRONTEND=noninteractive apt install -y gettext
# Checkout code with git
- uses: actions/checkout@v3
with:
ref: main
# Install go
- uses: actions/setup-go@v4
- name: Update pot and po files
uses: ubuntu/go-i18n@main
with:
go-version-file: go.mod
# Update po if needed
- name: Check po files
id: checkpo
run: |
set -eu
hasModif="false"
go generate ./internal/i18n/
# Exclude line diffs only
MODIFIED=$(git difftool -y -x "diff -Nup -I '^#: '" po/)
if [ -n "$MODIFIED" ]; then
hasModif="true"
fi
echo "modified=${hasModif}" >> $GITHUB_ENV
domain: "adsys"
entrypoints: "cmd/adsysd,cmd/admxgen,cmd/adwatchd"
- name: Check if there is a diff
id: po-diff
uses: canonical/desktop-engineering/gh-actions/common/has-diff@main
- name: Create Pull Request
if: ${{ env.modified == 'true' }}
if: ${{ steps.po-diff.outputs.diff == 'true' }}
uses: peter-evans/create-pull-request@v5
with:
commit-message: Auto update po files
Expand All @@ -55,7 +41,7 @@ jobs:
branch: auto-update-po
token: ${{ secrets.GITHUB_TOKEN }}
- name: Push branch
if: ${{ env.modified == 'true' }}
if: ${{ steps.po-diff.outputs.diff == 'true' }}
run: |
git push origin auto-update-po:main
Expand Down
31 changes: 16 additions & 15 deletions cmd/admxgen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,19 @@
package main

import (
"errors"
"fmt"
"os"
"strings"

"github.com/leonelquinteros/gotext"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"github.com/ubuntu/adsys/internal/ad/admxgen"
"github.com/ubuntu/adsys/internal/cmdhandler"
"github.com/ubuntu/adsys/internal/config"
"github.com/ubuntu/adsys/internal/i18n"
)

const viperPrefix = "ADMXGEN"
Expand All @@ -31,8 +32,8 @@ func main() {

rootCmd := cobra.Command{
Use: "admxgen COMMAND",
Short: i18n.G("Generate Active Directory admx and adml files"),
Long: i18n.G(`Generate ADMX and intermediary working files from a list of policy definition files.`),
Short: gotext.Get("Generate Active Directory admx and adml files"),
Long: gotext.Get(`Generate ADMX and intermediary working files from a list of policy definition files.`),
Args: cmdhandler.SubcommandsRequiredWithSuggestions,
RunE: cmdhandler.NoCmd,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
Expand All @@ -41,9 +42,9 @@ func main() {
},
}

rootCmd.PersistentFlags().CountP("verbose", "v", i18n.G("issue INFO (-v), DEBUG (-vv) or DEBUG with caller (-vvv) output"))
rootCmd.PersistentFlags().CountP("verbose", "v", gotext.Get("issue INFO (-v), DEBUG (-vv) or DEBUG with caller (-vvv) output"))
if err := bindFlags(viper, rootCmd.PersistentFlags()); err != nil {
log.Errorf(i18n.G("can't install command flag bindings: %v"), err)
log.Error(gotext.Get("can't install command flag bindings: %v", err))
os.Exit(2)
}

Expand All @@ -66,19 +67,19 @@ func main() {
func installExpand(rootCmd *cobra.Command, viper *viper.Viper) error {
cmd := &cobra.Command{
Use: "expand SOURCE DEST",
Short: i18n.G("Generates intermediary policy definition files"),
Long: i18n.G(`Generates an intermediary policy definition file into DEST directory from all the policy definition files in SOURCE directory, using the correct decoder.
Short: gotext.Get("Generates intermediary policy definition files"),
Long: gotext.Get(`Generates an intermediary policy definition file into DEST directory from all the policy definition files in SOURCE directory, using the correct decoder.
The generated definition file will be of the form expanded_policies.RELEASE.yaml`),
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
return admxgen.Expand(args[0], args[1], viper.GetString("root"), viper.GetString("current-session"))
},
}
cmd.Flags().StringP("root", "r", "/", i18n.G("root filesystem path to use. Default to /."))
cmd.Flags().StringP("current-session", "s", "", i18n.G(`current session to consider for dconf per-session
cmd.Flags().StringP("root", "r", "/", gotext.Get("root filesystem path to use. Default to /."))
cmd.Flags().StringP("current-session", "s", "", gotext.Get(`current session to consider for dconf per-session
overrides. Default to "".`))
if err := bindFlags(viper, cmd.Flags()); err != nil {
return fmt.Errorf(i18n.G("can't install command flag bindings: %v"), err)
return errors.New(gotext.Get("can't install command flag bindings: %v", err))
}

rootCmd.AddCommand(cmd)
Expand All @@ -89,17 +90,17 @@ func installAdmx(rootCmd *cobra.Command, viper *viper.Viper) error {
var autoDetectReleases, allowMissingKeys *bool
cmd := &cobra.Command{
Use: "admx CATEGORIES_DEF.YAML SOURCE DEST",
Short: i18n.G("Create finale admx and adml files"),
Long: i18n.G("Collects all intermediary policy definition files in SOURCE directory to create admx and adml templates in DEST, based on CATEGORIES_DEF.yaml."),
Short: gotext.Get("Create finale admx and adml files"),
Long: gotext.Get("Collects all intermediary policy definition files in SOURCE directory to create admx and adml templates in DEST, based on CATEGORIES_DEF.yaml."),
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
return admxgen.Generate(args[0], args[1], args[2], *autoDetectReleases, *allowMissingKeys)
},
}
autoDetectReleases = cmd.Flags().BoolP("auto-detect-releases", "a", false, i18n.G("override supported releases in categories definition file and will takes all yaml files in SOURCE directory and use the basename as their versions."))
allowMissingKeys = cmd.Flags().BoolP("allow-missing-keys", "k", false, i18n.G(`avoid fail but display a warning if some keys are not available in a release. This is the case when news keys are added to non-lts releases.`))
autoDetectReleases = cmd.Flags().BoolP("auto-detect-releases", "a", false, gotext.Get("override supported releases in categories definition file and will takes all yaml files in SOURCE directory and use the basename as their versions."))
allowMissingKeys = cmd.Flags().BoolP("allow-missing-keys", "k", false, gotext.Get(`avoid fail but display a warning if some keys are not available in a release. This is the case when news keys are added to non-lts releases.`))
if err := bindFlags(viper, cmd.Flags()); err != nil {
return fmt.Errorf(i18n.G("can't install command flag bindings: %v"), err)
return errors.New(gotext.Get("can't install command flag bindings: %v", err))
}

rootCmd.AddCommand(cmd)
Expand Down
8 changes: 4 additions & 4 deletions cmd/adsysd/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import (
"fmt"
"time"

"github.com/leonelquinteros/gotext"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/ubuntu/adsys/internal/cmdhandler"
"github.com/ubuntu/adsys/internal/config"
"github.com/ubuntu/adsys/internal/consts"
"github.com/ubuntu/adsys/internal/grpc/grpcerror"
"github.com/ubuntu/adsys/internal/i18n"
"github.com/ubuntu/decorate"
)

Expand Down Expand Up @@ -42,8 +42,8 @@ func New() *App {
a.ctx, a.cancel = context.WithCancel(context.Background())
a.rootCmd = cobra.Command{
Use: fmt.Sprintf("%s COMMAND", CmdName),
Short: i18n.G("AD integration client"),
Long: i18n.G(`Active Directory integration bridging toolset command line tool.`),
Short: gotext.Get("AD integration client"),
Long: gotext.Get(`Active Directory integration bridging toolset command line tool.`),
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
// command parsing has been successful. Returns runtime (or configuration) error now and so, don’t print usage.
a.rootCmd.SilenceUsage = true
Expand Down Expand Up @@ -90,7 +90,7 @@ func New() *App {
cmdhandler.InstallConfigFlag(&a.rootCmd, true)
cmdhandler.InstallSocketFlag(&a.rootCmd, a.viper, consts.DefaultSocket)

a.rootCmd.PersistentFlags().IntP("timeout", "t", consts.DefaultClientTimeout, i18n.G("time in seconds before cancelling the client request when the server gives no result. 0 for no timeout."))
a.rootCmd.PersistentFlags().IntP("timeout", "t", consts.DefaultClientTimeout, gotext.Get("time in seconds before cancelling the client request when the server gives no result. 0 for no timeout."))
decorate.LogOnError(a.viper.BindPFlag("client_timeout", a.rootCmd.PersistentFlags().Lookup("timeout")))

// subcommands
Expand Down
13 changes: 7 additions & 6 deletions cmd/adsysd/client/doc.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package client

import (
"errors"
"fmt"
"os"
"path/filepath"
Expand All @@ -10,18 +11,18 @@ import (
"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/html"
"github.com/gomarkdown/markdown/parser"
"github.com/leonelquinteros/gotext"
"github.com/spf13/cobra"
"github.com/ubuntu/adsys"
"github.com/ubuntu/adsys/doc"
"github.com/ubuntu/adsys/internal/adsysservice"
"github.com/ubuntu/adsys/internal/i18n"
)

func (a *App) installDoc() {
var format, dest *string
docCmd := &cobra.Command{
Use: "doc [CHAPTER]",
Short: i18n.G("Documentation"),
Short: gotext.Get("Documentation"),
Args: cobra.MaximumNArgs(1),
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 0 {
Expand Down Expand Up @@ -51,8 +52,8 @@ func (a *App) installDoc() {
return a.getDocumentation(chapter, *format, *dest)
},
}
format = docCmd.Flags().StringP("format", "f", "markdown", i18n.G("Format type (markdown, raw or html)."))
dest = docCmd.Flags().StringP("dest", "d", "", i18n.G("Write documentation file(s) to this directory."))
format = docCmd.Flags().StringP("format", "f", "markdown", gotext.Get("Format type (markdown, raw or html)."))
dest = docCmd.Flags().StringP("dest", "d", "", gotext.Get("Write documentation file(s) to this directory."))

a.rootCmd.AddCommand(docCmd)
}
Expand Down Expand Up @@ -132,10 +133,10 @@ func (a *App) getDocumentation(chapter, format, dest string) error {

// Dump documentation in a directory
if err = os.MkdirAll(dest, 0750); err != nil {
return fmt.Errorf(i18n.G("can't create %q"), dest)
return errors.New(gotext.Get("can't create %q", dest))
}
if err := os.WriteFile(filepath.Join(dest, filename+ext), []byte(out), 0600); err != nil {
return fmt.Errorf(i18n.G("can't write documentation chapter %q: %v"), filename+ext, err)
return errors.New(gotext.Get("can't write documentation chapter %q: %v", filename+ext, err))
}
}

Expand Down
46 changes: 23 additions & 23 deletions cmd/adsysd/client/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,27 @@ import (
"strings"

"github.com/fatih/color"
"github.com/leonelquinteros/gotext"
"github.com/spf13/cobra"
"github.com/ubuntu/adsys"
"github.com/ubuntu/adsys/internal/adsysservice"
"github.com/ubuntu/adsys/internal/cmdhandler"
"github.com/ubuntu/adsys/internal/consts"
log "github.com/ubuntu/adsys/internal/grpc/logstreamer"
"github.com/ubuntu/adsys/internal/i18n"
)

func (a *App) installPolicy() {
policyCmd := &cobra.Command{
Use: "policy COMMAND",
Short: i18n.G("Policy management"),
Short: gotext.Get("Policy management"),
Args: cmdhandler.SubcommandsRequiredWithSuggestions,
RunE: cmdhandler.NoCmd,
}

var distro *string
mainCmd := &cobra.Command{
Use: "admx lts-only|all",
Short: i18n.G("Dump windows policy definitions"),
Short: gotext.Get("Dump windows policy definitions"),
Args: cobra.ExactArgs(1),
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 0 {
Expand All @@ -40,13 +40,13 @@ func (a *App) installPolicy() {
},
RunE: func(cmd *cobra.Command, args []string) error { return a.getPolicyDefinitions(args[0], *distro) },
}
distro = mainCmd.Flags().StringP("distro", "", consts.DistroID, i18n.G("distro for which to retrieve policy definition."))
distro = mainCmd.Flags().StringP("distro", "", consts.DistroID, gotext.Get("distro for which to retrieve policy definition."))
policyCmd.AddCommand(mainCmd)

var details, all, nocolor, isMachine *bool
appliedCmd := &cobra.Command{
Use: "applied [USER_NAME]",
Short: i18n.G("Print last applied GPOs for current or given user/machine"),
Short: gotext.Get("Print last applied GPOs for current or given user/machine"),
Args: cmdhandler.ZeroOrNArgs(1),
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 0 {
Expand All @@ -63,24 +63,24 @@ func (a *App) installPolicy() {
return a.dumpPolicies(target, *details, *all, *nocolor, *isMachine)
},
}
details = appliedCmd.Flags().BoolP("details", "", false, i18n.G("show applied rules in addition to GPOs."))
all = appliedCmd.Flags().BoolP("all", "a", false, i18n.G("show overridden rules in each GPOs."))
nocolor = appliedCmd.Flags().BoolP("no-color", "", false, i18n.G("don't display colorized version."))
isMachine = appliedCmd.Flags().BoolP("machine", "m", false, i18n.G("show applied rules to the machine."))
details = appliedCmd.Flags().BoolP("details", "", false, gotext.Get("show applied rules in addition to GPOs."))
all = appliedCmd.Flags().BoolP("all", "a", false, gotext.Get("show overridden rules in each GPOs."))
nocolor = appliedCmd.Flags().BoolP("no-color", "", false, gotext.Get("don't display colorized version."))
isMachine = appliedCmd.Flags().BoolP("machine", "m", false, gotext.Get("show applied rules to the machine."))
policyCmd.AddCommand(appliedCmd)
cmdhandler.RegisterAlias(appliedCmd, &a.rootCmd)

debugCmd := &cobra.Command{
Use: "debug",
Short: i18n.G("Debug various policy infos"),
Short: gotext.Get("Debug various policy infos"),
Hidden: true,
Args: cmdhandler.SubcommandsRequiredWithSuggestions,
RunE: cmdhandler.NoCmd,
}
policyCmd.AddCommand(debugCmd)
gpoListCmd := &cobra.Command{
Use: "gpolist-script",
Short: i18n.G("Write GPO list python embeeded script in current directory"),
Short: gotext.Get("Write GPO list python embeeded script in current directory"),
Args: cobra.NoArgs,
ValidArgsFunction: cmdhandler.NoValidArgs,
RunE: func(cmd *cobra.Command, args []string) error { return a.dumpGPOListScript() },
Expand All @@ -90,7 +90,7 @@ func (a *App) installPolicy() {
var updateMachine, updateAll *bool
updateCmd := &cobra.Command{
Use: "update [USER_NAME KERBEROS_TICKET_PATH]",
Short: i18n.G("Updates/Create a policy for current user or given user with its kerberos ticket"),
Short: gotext.Get("Updates/Create a policy for current user or given user with its kerberos ticket"),
Args: cmdhandler.ZeroOrNArgs(2),
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// All and machine options don’t take arguments
Expand All @@ -117,15 +117,15 @@ func (a *App) installPolicy() {
return a.update(*updateMachine, *updateAll, user, krb5cc)
},
}
updateMachine = updateCmd.Flags().BoolP("machine", "m", false, i18n.G("machine updates the policy of the computer."))
updateAll = updateCmd.Flags().BoolP("all", "a", false, i18n.G("all updates the policy of the computer and all the logged in users. -m or USER_NAME/TICKET cannot be used with this option."))
updateMachine = updateCmd.Flags().BoolP("machine", "m", false, gotext.Get("machine updates the policy of the computer."))
updateAll = updateCmd.Flags().BoolP("all", "a", false, gotext.Get("all updates the policy of the computer and all the logged in users. -m or USER_NAME/TICKET cannot be used with this option."))
policyCmd.AddCommand(updateCmd)
cmdhandler.RegisterAlias(updateCmd, &a.rootCmd)

var purgeMachine, purgeAll *bool
purgeCmd := &cobra.Command{
Use: "purge [USER_NAME]",
Short: i18n.G("Purges policies for the current user or a specified one"),
Short: gotext.Get("Purges policies for the current user or a specified one"),
Args: cmdhandler.ZeroOrNArgs(1),
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// All and machine options don’t take arguments
Expand All @@ -144,8 +144,8 @@ func (a *App) installPolicy() {
return a.purge(*purgeMachine, *purgeAll, user)
},
}
purgeMachine = purgeCmd.Flags().BoolP("machine", "m", false, i18n.G("machine purges the policy of the computer."))
purgeAll = purgeCmd.Flags().BoolP("all", "a", false, i18n.G("all purges the policy of the computer and all the logged in users. -m or USER_NAME cannot be used with this option."))
purgeMachine = purgeCmd.Flags().BoolP("machine", "m", false, gotext.Get("machine purges the policy of the computer."))
purgeAll = purgeCmd.Flags().BoolP("all", "a", false, gotext.Get("all purges the policy of the computer and all the logged in users. -m or USER_NAME cannot be used with this option."))
purgeCmd.MarkFlagsMutuallyExclusive("machine", "all")
policyCmd.AddCommand(purgeCmd)

Expand Down Expand Up @@ -305,9 +305,9 @@ func colorizePolicies(policies string) (string, error) {
indent := " - "
if disabledKey {
if currentPoliciesType == "dconf" {
e = fmt.Sprintf(i18n.G("%s: Locked to system default"), e)
e = gotext.Get("%s: Locked to system default", e)
} else {
e = fmt.Sprintf(i18n.G("%s: Disabled"), e)
e = gotext.Get("%s: Disabled", e)
}
}
if overridden {
Expand Down Expand Up @@ -362,10 +362,10 @@ func (s *stringsBuilderWithError) Println(l string) {
func (a *App) update(isComputer, updateAll bool, target, krb5cc string) error {
// incompatible options
if updateAll && (isComputer || target != "" || krb5cc != "") {
return errors.New(i18n.G("machine or user arguments cannot be used with update all"))
return errors.New(gotext.Get("machine or user arguments cannot be used with update all"))
}
if isComputer && (target != "" || krb5cc != "") {
return errors.New(i18n.G("user arguments cannot be used with machine update"))
return errors.New(gotext.Get("user arguments cannot be used with machine update"))
}

client, err := adsysservice.NewClient(a.config.Socket, a.getTimeout())
Expand Down Expand Up @@ -413,10 +413,10 @@ func (a *App) update(isComputer, updateAll bool, target, krb5cc string) error {
func (a *App) purge(isComputer, purgeAll bool, target string) error {
// incompatible options
if purgeAll && target != "" {
return errors.New(i18n.G("machine or user arguments cannot be used with update all"))
return errors.New(gotext.Get("machine or user arguments cannot be used with update all"))
}
if isComputer && target != "" {
return errors.New(i18n.G("user arguments cannot be used with machine update"))
return errors.New(gotext.Get("user arguments cannot be used with machine update"))
}

client, err := adsysservice.NewClient(a.config.Socket, a.getTimeout())
Expand Down
Loading

0 comments on commit 76d2053

Please sign in to comment.