Skip to content

Commit

Permalink
Add an option to constrain poe2arb version for a project
Browse files Browse the repository at this point in the history
  • Loading branch information
KrzysztofMamak authored Nov 6, 2024
2 parents 61343e7 + 9e9b916 commit 9f7795f
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 31 deletions.
23 changes: 20 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ poe2arb convert io --lang en < Hello_World_English.json > lib/l10n/app_en.arb

### Seeding POEditor project

**EXPERIMENTAL FEATURE**
> [!WARNING]
> **EXPERIMENTAL FEATURE**
If you're setting up a project from some template code, you probably already have some ARB files that need
to be imported into the POEditor project. Using the POEditor's built-in tool won't give a satisfying result,
Expand All @@ -96,8 +97,8 @@ with already populated translations is inadvisable.

## Syntax & supported features

Term name must be a valid Dart field name, additionaly, it must start with a
lowercase letter ([Flutter's constraint][term-name-constraint]).
> [!IMPORTANT]
> Term name must be a valid Dart field name, additionaly, it must start with a lowercase letter ([Flutter's constraint][term-name-constraint]).
### Term prefix filtering

Expand Down Expand Up @@ -150,6 +151,7 @@ Available placeholder types:
**Only template files can define placeholders with their type and format.** In non-template languages, placeholders' types and formats
are ignored and no logical errors are reported.

> [!NOTE]
> \*If you're using Flutter 3.5 or older, you need to specify format for numeric placeholders.
> Otherwise `flutter gen-l10n` will fail. You can look at the legacy placeholder syntax diagrams
> [for placeholders here][flutter35-placeholders-diagram] and for [plural's `count` placeholders here][flutter35-count-placeholders-diagram].
Expand Down Expand Up @@ -198,6 +200,20 @@ other: Andy has {count} kilograms of {fruit}.

You must provide at least `other` plural category for your translations, otherwise it won't be converted.

## Constraining version for a Flutter project

You can constrain poe2arb version by specifying `poe2arb-version` option in `l10n.yaml`.

```yaml
# Available formats:
poe2arb-version: "0.5.1" # Specific version
poe2arb-version: ">=0.5.1, <0.7" # Version range
poe2arb-version: ">0.5.1" # Minimum version
poe2arb-version: "<=0.7" # Maximum version
```
You can find more information about version constraints format [here][go-version].
## Contributing
### Formatting
Expand Down Expand Up @@ -255,6 +271,7 @@ git push origin v0.1.1
[flutter35-count-placeholders-diagram]: https://github.com/leancodepl/poe2arb/blob/24be17d6721698526c879b3fada87183b359e8e8/art/count-placeholder-syntax.svg
[placeholder-diagram-img]: art/placeholder-syntax.svg
[count-placeholder-diagram-img]: art/count-placeholder-syntax.svg
[go-version]: https://github.com/hashicorp/go-version
[gofumpt]: https://github.com/mvdan/gofumpt
[gofmt]: https://pkg.go.dev/cmd/gofmt
[staticcheck]: https://staticcheck.io
80 changes: 80 additions & 0 deletions cmd/flutter_config_version_guard.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package cmd

import (
"context"
"fmt"
"os"

"github.com/hashicorp/go-version"
"github.com/leancodepl/poe2arb/flutter"
"github.com/spf13/cobra"
)

type flutterConfigKey struct{}

type flutterConfigVersionGuard struct{}

func flutterConfigFromCommand(cmd *cobra.Command) *flutter.FlutterConfig {
return cmd.Context().Value(flutterConfigKey{}).(*flutter.FlutterConfig)
}

// GetFlutterConfigAndEnsureSufficientVersion gets Flutter project configuration,
// puts it in the command's context and verifies if poe2arb version matches constraint.
func (fcvg flutterConfigVersionGuard) GetFlutterConfigAndEnsureSufficientVersion(cmd *cobra.Command, _ []string) error {
log := getLogger(cmd)

logSub := log.Info("loading Flutter config").Sub()

flutterCfg, err := fcvg.getFlutterConfig()
if err != nil {
logSub.Error("failed: " + err.Error())
return err
}

err = fcvg.ensureSufficientVersion(flutterCfg.L10n.Poe2ArbVersion)
if err != nil {
logSub.Error("failed: " + err.Error())
return err
}

ctx := context.WithValue(cmd.Context(), flutterConfigKey{}, flutterCfg)
cmd.SetContext(ctx)

return nil
}

func (flutterConfigVersionGuard) ensureSufficientVersion(versionConstraint string) error {
if versionConstraint == "" {
return nil
}

constraint, err := version.NewConstraint(versionConstraint)
if err != nil {
return fmt.Errorf("invalid poe2arb-version format in l10n.yaml: %s", versionConstraint)
}

version, err := version.NewVersion(Version)
if err != nil {
return fmt.Errorf("poe2arb version format is invalid: %w", err)
}

if !constraint.Check(version) {
return fmt.Errorf("poe2arb version %s does not match constraint %s defined in l10n.yaml", version, versionConstraint)
}

return nil
}

func (flutterConfigVersionGuard) getFlutterConfig() (*flutter.FlutterConfig, error) {
workDir, err := os.Getwd()
if err != nil {
return nil, err
}

flutterCfg, err := flutter.NewFromDirectory(workDir)
if err != nil {
return nil, err
}

return flutterCfg, nil
}
20 changes: 2 additions & 18 deletions cmd/poe.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var (
SilenceErrors: true,
SilenceUsage: true,
RunE: runPoe,
PreRunE: versionGuard.GetFlutterConfigAndEnsureSufficientVersion,
}
termPrefixRegexp = regexp.MustCompile("[a-zA-Z]*")
)
Expand Down Expand Up @@ -103,10 +104,7 @@ func getOptionsSelector(cmd *cobra.Command) (*poeOptionsSelector, error) {
return nil, err
}

flutterCfg, err := getFlutterConfig()
if err != nil {
return nil, err
}
flutterCfg := flutterConfigFromCommand(cmd)

return &poeOptionsSelector{
flags: cmd.Flags(),
Expand All @@ -115,20 +113,6 @@ func getOptionsSelector(cmd *cobra.Command) (*poeOptionsSelector, error) {
}, nil
}

func getFlutterConfig() (*flutter.FlutterConfig, error) {
workDir, err := os.Getwd()
if err != nil {
return nil, err
}

flutterCfg, err := flutter.NewFromDirectory(workDir)
if err != nil {
return nil, err
}

return flutterCfg, nil
}

type poeCommand struct {
options *poeOptions
client *poeditor.Client
Expand Down
19 changes: 10 additions & 9 deletions cmd/poe2arb.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,29 @@ import (
"github.com/spf13/cobra"
)

var rootCmd = &cobra.Command{
Use: "poe2arb",
Short: "POEditor JSON to Flutter ARB converter",
}

type ctxKey int
var (
rootCmd = &cobra.Command{
Use: "poe2arb",
Short: "POEditor JSON to Flutter ARB converter",
}
versionGuard = flutterConfigVersionGuard{}
)

const loggerKey = ctxKey(1)
type loggerKey struct{}

func Execute(logger *log.Logger) {
rootCmd.AddCommand(convertCmd)
rootCmd.AddCommand(poeCmd)
rootCmd.AddCommand(seedCmd)
rootCmd.AddCommand(versionCmd)

ctx := context.WithValue(context.Background(), loggerKey, logger)
ctx := context.WithValue(context.Background(), loggerKey{}, logger)

if err := rootCmd.ExecuteContext(ctx); err != nil {
os.Exit(1)
}
}

func getLogger(cmd *cobra.Command) *log.Logger {
return cmd.Context().Value(loggerKey).(*log.Logger)
return cmd.Context().Value(loggerKey{}).(*log.Logger)
}
1 change: 1 addition & 0 deletions cmd/seed.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var seedCmd = &cobra.Command{
SilenceErrors: true,
SilenceUsage: true,
RunE: runSeed,
PreRunE: versionGuard.GetFlutterConfigAndEnsureSufficientVersion,
}

func init() {
Expand Down
1 change: 1 addition & 0 deletions flutter/flutter_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type L10n struct {
POEditorProjectID string `yaml:"poeditor-project-id"`
POEditorLangs []string `yaml:"poeditor-langs"`
POEditorTermPrefix string `yaml:"poeditor-term-prefix"`
Poe2ArbVersion string `yaml:"poe2arb-version"`
}

func newDefaultL10n() *L10n {
Expand Down
3 changes: 2 additions & 1 deletion flutter/flutter_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func TestNewFromDirectory(t *testing.T) {
err = os.WriteFile(filepath.Join(dir, "pubspec.yaml"), []byte{}, 0o666)
assert.NoError(t, err)

l10nContents := `{arb-dir: this-is/arb-dir/test, poeditor-project-id: 123123}`
l10nContents := `{arb-dir: this-is/arb-dir/test, poeditor-project-id: 123123, poe2arb-version: ">=0.5.0, <0.7"}`
err = os.WriteFile(filepath.Join(dir, "l10n.yaml"), []byte(l10nContents), 0o666)
assert.NoError(t, err)

Expand All @@ -75,5 +75,6 @@ func TestNewFromDirectory(t *testing.T) {

assert.Equal(t, "this-is/arb-dir/test", cfg.L10n.ARBDir)
assert.Equal(t, "123123", cfg.L10n.POEditorProjectID)
assert.Equal(t, ">=0.5.0, <0.7", cfg.L10n.Poe2ArbVersion)
})
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.21
require (
github.com/TwiN/go-color v1.4.0
github.com/caarlos0/env/v6 v6.10.1
github.com/hashicorp/go-version v1.7.0
github.com/spf13/cobra v1.6.1
github.com/wk8/go-ordered-map/v2 v2.1.1
gopkg.in/yaml.v3 v3.0.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
Expand Down

0 comments on commit 9f7795f

Please sign in to comment.