From 0d05e16e8c53a91d279d2443df4300f9e41f9409 Mon Sep 17 00:00:00 2001 From: Albert Wolszon Date: Mon, 23 Oct 2023 15:17:32 +0200 Subject: [PATCH 1/7] Add term-prefix setting and filtering --- cmd/convert.go | 11 ++- cmd/poe.go | 37 ++++++--- cmd/poe_options_selector.go | 25 +++++- converter/converter.go | 35 ++++++--- converter/converter_test.go | 27 +++++-- converter/testdata/filter-noprefix.golden | 12 +++ converter/testdata/filter-noprefix.input | 34 ++++++++ converter/testdata/filter-prefix.golden | 12 +++ converter/testdata/filter-prefix.input | 34 ++++++++ flutter/flutter_config.go | 5 +- smoke_test/pubspec.lock | 94 +++++++++++++++-------- 11 files changed, 259 insertions(+), 67 deletions(-) create mode 100644 converter/testdata/filter-noprefix.golden create mode 100644 converter/testdata/filter-noprefix.input create mode 100644 converter/testdata/filter-prefix.golden create mode 100644 converter/testdata/filter-prefix.input diff --git a/cmd/convert.go b/cmd/convert.go index 1dddc6c..f9b51ef 100644 --- a/cmd/convert.go +++ b/cmd/convert.go @@ -29,6 +29,7 @@ func init() { convertCmd.PersistentFlags().StringP(langFlag, "l", "", "Language of the input") convertCmd.MarkPersistentFlagRequired(langFlag) + convertCmd.PersistentFlags().StringP(termPrefixFlag, "t", "", "POEditor term prefix") convertCmd.PersistentFlags().Bool(noTemplateFlag, false, "Whether the output should NOT be generated as a template ARB") convertCmd.AddCommand(convertIoCmd) @@ -37,8 +38,14 @@ func init() { func runConvertIo(cmd *cobra.Command, args []string) error { lang, _ := cmd.Flags().GetString(langFlag) noTemplate, _ := cmd.Flags().GetBool(noTemplateFlag) - - conv := converter.NewConverter(os.Stdin, lang, !noTemplate, true) + termPrefix, _ := cmd.Flags().GetString(termPrefixFlag) + + conv := converter.NewConverter(os.Stdin, &converter.ConverterOptions{ + Lang: lang, + Template: !noTemplate, + RequireResourceAttributes: true, + TermPrefix: termPrefix, + }) return conv.Convert(os.Stdout) } diff --git a/cmd/poe.go b/cmd/poe.go index 7e2791b..ad9d9b7 100644 --- a/cmd/poe.go +++ b/cmd/poe.go @@ -5,6 +5,7 @@ import ( "net/http" "os" "path" + "regexp" "strings" "github.com/leancodepl/poe2arb/converter" @@ -15,18 +16,22 @@ import ( "github.com/spf13/cobra" ) -var poeCmd = &cobra.Command{ - Use: "poe", - Short: "Exports POEditor terms and converts them to ARB. " + - "Must be run from the Flutter project root directory or its subdirectory.", - SilenceErrors: true, - SilenceUsage: true, - RunE: runPoe, -} +var ( + poeCmd = &cobra.Command{ + Use: "poe", + Short: "Exports POEditor terms and converts them to ARB. " + + "Must be run from the Flutter project root directory or its subdirectory.", + SilenceErrors: true, + SilenceUsage: true, + RunE: runPoe, + } + termPrefixRegexp = regexp.MustCompile("[a-z]*") +) const ( projectIDFlag = "project-id" tokenFlag = "token" + termPrefixFlag = "term-prefix" outputDirFlag = "output-dir" overrideLangsFlag = "langs" ) @@ -34,6 +39,7 @@ const ( func init() { poeCmd.Flags().StringP(projectIDFlag, "p", "", "POEditor project ID") poeCmd.Flags().StringP(tokenFlag, "t", "", "POEditor API token") + poeCmd.Flags().StringP(termPrefixFlag, "", "", "POEditor term prefix") poeCmd.Flags().StringP(outputDirFlag, "o", "", `Output directory [default: "."]`) poeCmd.Flags().StringSliceP(overrideLangsFlag, "", []string{}, "Override downloaded languages") } @@ -75,7 +81,7 @@ func runPoe(cmd *cobra.Command, args []string) error { for _, lang := range langs { template := options.TemplateLocale == lang.Code - err := poeCmd.ExportLanguage(lang, template, options.RequireResourceAttributes) + err := poeCmd.ExportLanguage(lang, template) if err != nil { msg := fmt.Sprintf("exporting %s (%s) language", lang.Name, lang.Code) return errors.Wrap(err, msg) @@ -154,6 +160,10 @@ func validatePoeOptions(options *poeOptions) []error { errs = append(errs, errors.New("no POEditor API token provided")) } + if termPrefixRegexp.MatchString(options.TermPrefix) { + errs = append(errs, errors.New("term prefix must contain only lowercase letters or be empty")) + } + return errs } @@ -209,7 +219,7 @@ func (c *poeCommand) EnsureOutputDirectory() error { return nil } -func (c *poeCommand) ExportLanguage(lang poeditor.Language, template, requireResourceAttributes bool) error { +func (c *poeCommand) ExportLanguage(lang poeditor.Language, template bool) error { logSub := c.log.Info("fetching JSON export for %s (%s)", lang.Name, lang.Code).Sub() url, err := c.client.GetExportURL(c.options.ProjectID, lang.Code) if err != nil { @@ -232,7 +242,12 @@ func (c *poeCommand) ExportLanguage(lang poeditor.Language, template, requireRes convertLogSub := logSub.Info("converting JSON to ARB").Sub() - conv := converter.NewConverter(resp.Body, lang.Code, template, requireResourceAttributes) + conv := converter.NewConverter(resp.Body, &converter.ConverterOptions{ + Lang: lang.Code, + Template: template, + RequireResourceAttributes: c.options.RequireResourceAttributes, + TermPrefix: c.options.TermPrefix, + }) err = conv.Convert(file) if err != nil { convertLogSub.Error(err.Error()) diff --git a/cmd/poe_options_selector.go b/cmd/poe_options_selector.go index 9178682..d3c8153 100644 --- a/cmd/poe_options_selector.go +++ b/cmd/poe_options_selector.go @@ -20,8 +20,10 @@ type poeOptionsSelector struct { // poeOptions describes options passed or otherwise obtained to the poe command. type poeOptions struct { - ProjectID string - Token string + ProjectID string + Token string + TermPrefix string + ARBPrefix string TemplateLocale string OutputDir string @@ -41,6 +43,11 @@ func (s *poeOptionsSelector) SelectOptions() (*poeOptions, error) { return nil, err } + termPrefix, err := s.SelectTermPrefix() + if err != nil { + return nil, err + } + arbPrefix, templateLocale, err := s.SelectARBPrefixAndTemplate() if err != nil { return nil, err @@ -61,6 +68,7 @@ func (s *poeOptionsSelector) SelectOptions() (*poeOptions, error) { return &poeOptions{ ProjectID: projectID, Token: token, + TermPrefix: termPrefix, ARBPrefix: arbPrefix, TemplateLocale: templateLocale, OutputDir: outputDir, @@ -95,6 +103,19 @@ func (s *poeOptionsSelector) SelectToken() (string, error) { return s.env.Token, nil } +// SelectTermPrefix returns POEditor term prefix option from available sources. +func (s *poeOptionsSelector) SelectTermPrefix() (string, error) { + fromCmd, err := s.flags.GetString(termPrefixFlag) + if err != nil { + return "", err + } + if fromCmd != "" { + return fromCmd, nil + } + + return s.l10n.POEditorTermPrefix, nil +} + // SelectARBPrefix returns ARB files prefix option from available sources. func (s *poeOptionsSelector) SelectARBPrefixAndTemplate() (prefix, templateLocale string, err error) { prefix, err = prefixFromTemplateFileName(s.l10n.TemplateArbFile) diff --git a/converter/converter.go b/converter/converter.go index cbee224..7d1d608 100644 --- a/converter/converter.go +++ b/converter/converter.go @@ -4,6 +4,7 @@ package converter import ( "encoding/json" "io" + "regexp" "strings" "github.com/pkg/errors" @@ -13,25 +14,30 @@ import ( type Converter struct { input io.Reader - lang string - template bool - + lang string + template bool requireResourceAttributes bool + termPrefix string +} + +type ConverterOptions struct { + Lang string + Template bool + RequireResourceAttributes bool + TermPrefix string } func NewConverter( input io.Reader, - lang string, - template bool, - requireResourceAttributes bool, + options *ConverterOptions, ) *Converter { return &Converter{ input: input, - lang: lang, - template: template, - - requireResourceAttributes: requireResourceAttributes, + lang: options.Lang, + template: options.Template, + requireResourceAttributes: options.RequireResourceAttributes, + termPrefix: options.TermPrefix, } } @@ -45,9 +51,18 @@ func (c *Converter) Convert(output io.Writer) error { arb := orderedmap.New[string, any]() arb.Set(localeKey, c.lang) + prefixedRegexp := regexp.MustCompile("(?:(.+):)?(.*)") var errs []error for _, term := range jsonContents { + // Filter by term prefix + matches := prefixedRegexp.FindStringSubmatch(term.Term) + if matches[1] == c.termPrefix { + term.Term = matches[2] + } else { + continue + } + message, err := c.parseTerm(term) if err != nil { err = errors.Wrapf(err, `decoding term "%s" failed`, term.Term) diff --git a/converter/converter_test.go b/converter/converter_test.go index fc1713e..8e842e7 100644 --- a/converter/converter_test.go +++ b/converter/converter_test.go @@ -29,6 +29,11 @@ func TestConverterConvert(t *testing.T) { template := !strings.Contains(testname, "-no-template") requireResourceAttributes := strings.Contains(testname, "-req-attrs") + var termPrefix string + if strings.Contains(testname, "-prefix") { + termPrefix = "prefix" + } + goldenfile := filepath.Join("testdata", testname+".golden") golden, err := os.ReadFile(goldenfile) if err != nil { @@ -38,7 +43,7 @@ func TestConverterConvert(t *testing.T) { expect := string(golden) // Actual test - actual, err := convert(t, string(source), template, requireResourceAttributes) + actual, err := convert(t, string(source), template, requireResourceAttributes, termPrefix) assert.NoError(t, err) assert.Equal(t, expect, actual) @@ -64,7 +69,7 @@ func TestConverterConvert(t *testing.T) { ` t.Run("issue 41 template", func(t *testing.T) { - actual, err := convert(t, issue41Source, true, false) + actual, err := convert(t, issue41Source, true, false, "") assert.Error(t, err) assert.EqualError(t, err, `decoding term "testPlural" failed: missing "other" plural category`) @@ -72,17 +77,27 @@ func TestConverterConvert(t *testing.T) { }) t.Run("issue 41 non-template", func(t *testing.T) { - actual, err := convert(t, issue41Source, false, false) + actual, err := convert(t, issue41Source, false, false, "") assert.NoError(t, err) assert.Equal(t, "{\n \"@@locale\": \"en\"\n}\n", actual) }) } -func convert(t *testing.T, input string, template bool, requireResourceAttributes bool) (converted string, err error) { +func convert( + t *testing.T, + input string, + template bool, + requireResourceAttributes bool, + termPrefix string, +) (converted string, err error) { reader := strings.NewReader(input) - conv := converter.NewConverter(reader, "en", template, requireResourceAttributes) - + conv := converter.NewConverter(reader, &converter.ConverterOptions{ + Lang: "en", + Template: template, + RequireResourceAttributes: requireResourceAttributes, + TermPrefix: termPrefix, + }) out := new(bytes.Buffer) err = conv.Convert(out) diff --git a/converter/testdata/filter-noprefix.golden b/converter/testdata/filter-noprefix.golden new file mode 100644 index 0000000..2e72668 --- /dev/null +++ b/converter/testdata/filter-noprefix.golden @@ -0,0 +1,12 @@ +{ + "@@locale": "en", + "fooBar": "Content", + "fooBarWithParam": "That's a {param}", + "@fooBarWithParam": { + "placeholders": { + "param": { + "type": "String" + } + } + } +} diff --git a/converter/testdata/filter-noprefix.input b/converter/testdata/filter-noprefix.input new file mode 100644 index 0000000..5d6d4ff --- /dev/null +++ b/converter/testdata/filter-noprefix.input @@ -0,0 +1,34 @@ +[ + { + "term": "fooBar", + "definition": "Content", + "context": "", + "term_plural": "", + "reference": "", + "comment": "" + }, + { + "term": "fooBarWithParam", + "definition": "That's a {param}", + "context": "", + "term_plural": "", + "reference": "", + "comment": "" + }, + { + "term": "prefix:prefixedFooBar", + "definition": "Other content", + "context": "", + "term_plural": "", + "reference": "", + "comment": "" + }, + { + "term": "prefix:prefixedFooBarWithParam", + "definition": "This is {param}", + "context": "", + "term_plural": "", + "reference": "", + "comment": "" + } +] diff --git a/converter/testdata/filter-prefix.golden b/converter/testdata/filter-prefix.golden new file mode 100644 index 0000000..d87a934 --- /dev/null +++ b/converter/testdata/filter-prefix.golden @@ -0,0 +1,12 @@ +{ + "@@locale": "en", + "prefixedFooBar": "Other content", + "prefixedFooBarWithParam": "This is {param}", + "@prefixedFooBarWithParam": { + "placeholders": { + "param": { + "type": "String" + } + } + } +} diff --git a/converter/testdata/filter-prefix.input b/converter/testdata/filter-prefix.input new file mode 100644 index 0000000..5d6d4ff --- /dev/null +++ b/converter/testdata/filter-prefix.input @@ -0,0 +1,34 @@ +[ + { + "term": "fooBar", + "definition": "Content", + "context": "", + "term_plural": "", + "reference": "", + "comment": "" + }, + { + "term": "fooBarWithParam", + "definition": "That's a {param}", + "context": "", + "term_plural": "", + "reference": "", + "comment": "" + }, + { + "term": "prefix:prefixedFooBar", + "definition": "Other content", + "context": "", + "term_plural": "", + "reference": "", + "comment": "" + }, + { + "term": "prefix:prefixedFooBarWithParam", + "definition": "This is {param}", + "context": "", + "term_plural": "", + "reference": "", + "comment": "" + } +] diff --git a/flutter/flutter_config.go b/flutter/flutter_config.go index 926d81b..876da53 100644 --- a/flutter/flutter_config.go +++ b/flutter/flutter_config.go @@ -29,8 +29,9 @@ type L10n struct { // custom options - POEditorProjectID string `yaml:"poeditor-project-id"` - POEditorLangs []string `yaml:"poeditor-langs"` + POEditorProjectID string `yaml:"poeditor-project-id"` + POEditorLangs []string `yaml:"poeditor-langs"` + POEditorTermPrefix string `yaml:"poeditor-term-prefix"` } func newDefaultL10n() *L10n { diff --git a/smoke_test/pubspec.lock b/smoke_test/pubspec.lock index b26a424..f9fc635 100644 --- a/smoke_test/pubspec.lock +++ b/smoke_test/pubspec.lock @@ -5,42 +5,48 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.2" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted version: "1.3.1" flutter: @@ -62,37 +68,42 @@ packages: dependency: transitive description: name: intl - url: "https://pub.dartlang.org" + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + url: "https://pub.dev" source: hosted - version: "0.17.0" + version: "0.18.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.5.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.8.3" sky_engine: dependency: transitive description: flutter @@ -102,50 +113,65 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + url: "https://pub.dev" source: hosted - version: "0.4.12" + version: "0.6.0" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "0.1.4-beta" sdks: - dart: ">=2.18.4 <3.0.0" + dart: ">=3.1.0-185.0.dev <4.0.0" From df94d81672bd261c2a26575c2a8bc29a991923f8 Mon Sep 17 00:00:00 2001 From: Albert Wolszon Date: Mon, 23 Oct 2023 15:22:46 +0200 Subject: [PATCH 2/7] Update LICENSE year to 2023 --- LICENSE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 8eaa729..85a0e0e 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2022 LeanCode Sp. z o.o. + Copyright 2023 LeanCode Sp. z o.o. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -198,4 +198,4 @@ 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. \ No newline at end of file + limitations under the License. From 4867ece06028aa9a29407a69c9e5f54d16c87d12 Mon Sep 17 00:00:00 2001 From: Albert Wolszon Date: Mon, 23 Oct 2023 15:36:53 +0200 Subject: [PATCH 3/7] Remove short term-prefix flag from poe2arb convert --- cmd/convert.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/convert.go b/cmd/convert.go index f9b51ef..5091af9 100644 --- a/cmd/convert.go +++ b/cmd/convert.go @@ -29,7 +29,7 @@ func init() { convertCmd.PersistentFlags().StringP(langFlag, "l", "", "Language of the input") convertCmd.MarkPersistentFlagRequired(langFlag) - convertCmd.PersistentFlags().StringP(termPrefixFlag, "t", "", "POEditor term prefix") + convertCmd.PersistentFlags().StringP(termPrefixFlag, "", "", "POEditor term prefix") convertCmd.PersistentFlags().Bool(noTemplateFlag, false, "Whether the output should NOT be generated as a template ARB") convertCmd.AddCommand(convertIoCmd) From 2a005de7b2c771fde1198c9ab910a5129c068c19 Mon Sep 17 00:00:00 2001 From: Albert Wolszon Date: Mon, 23 Oct 2023 16:31:00 +0200 Subject: [PATCH 4/7] Add description of terms filter to README --- README.md | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 46be1ca..8298141 100644 --- a/README.md +++ b/README.md @@ -52,12 +52,13 @@ into your Flutter workspace in one command: If a command-line flag is not specified, an environment variable is used, then `l10n.yaml` option, then it fallbacks to default. -| Description | Flag | Env | `l10n.yaml` | -|-------------------------------------------------------------------------------------------------------------------|------------------------|------------------|-----------------------| -| **Required.** POEditor project ID. It is visible in the URL of the project on POEditor website. | `-p`
`--project-id` | | `poeditor-project-id` | -| **Required.** POEditor API read-only access token. Available in [Account settings > API access][poeditor-tokens]. | `-t`
`--token` | `POEDITOR_TOKEN` | | -| ARB files output directory.
Defaults to current directory. | `-o`
`--output-dir` | | `arb-dir` | -| Exported languages override.
Defaults to using all languages from POEditor. | `--langs` | | `poeditor-langs` | +| Description | Flag | Env | `l10n.yaml` | +|-------------------------------------------------------------------------------------------------------------------|------------------------|------------------|------------------------| +| **Required.** POEditor project ID. It is visible in the URL of the project on POEditor website. | `-p`
`--project-id` | | `poeditor-project-id` | +| **Required.** POEditor API read-only access token. Available in [Account settings > API access][poeditor-tokens]. | `-t`
`--token` | `POEDITOR_TOKEN` | | +| ARB files output directory.
Defaults to current directory. | `-o`
`--output-dir` | | `arb-dir` | +| Exported languages override.
Defaults to using all languages from POEditor. | `--langs` | | `poeditor-langs` | +| Term prefix, used to filter generated messages.
Defaults to empty. | `--term-prefix` | | `poeditor-term-prefix` | ### Conversion @@ -69,6 +70,8 @@ For conversion, you need to pass the translation file language in the By default, a template ARB file is generated. So no empty message is skipped and attributes are generated. If you want to skip that, pass `--no-template` flag. +You may filter terms with `--term-prefix`. Defaults to empty (no prefix). + Currently, only an stdin/stdout is supported for the `poe2arb convert` command. ``` @@ -80,6 +83,29 @@ poe2arb convert io --lang en < Hello_World_English.json > lib/l10n/app_en.arb 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 + +If you wish to use one POEditor project for multiple packages, ideally you do not want +one package's terms to pollute all other packages. This is what term prefixes are for. + +Term names in POEditor can be defined starting with a prefix (only letters), followed by a colon `:`. +E.g. `loans:helpPage_title` or `design_system:modalClose`. Then, in your `l10n.yaml` or with the `--term-prefix` flag you may +define which terms should be imported, filtered by the prefix. + +If you don't pass a prefix to `poe2arb` (or pass an empty one), it will only import the terms that have no prefix. If you pass +prefix to `poe2arb`, it will import only the terms with this prefix. + +
Examples + +| Term name in POEditor | `--term-prefix` or
`poeditor-term-prefix` (`l10n.yaml`) | Message name in ARB | +|-----------------------|------------------------------------------------------------|---------------------| +| `appTitle` | none | `appTitle` | +| `somePrefix:appTitle` | none | not imported | +| `appTitle` | `somePrefix` | not imported | +| `somePrefix:appTitle` | `somePrefix` | `appTitle` | + +
+ ### Placeholders Placeholders can be as simple as a text between brackets, but they can also be From 17b12db2c72faebb1b97f67e01afcac83e4fcf9e Mon Sep 17 00:00:00 2001 From: Albert Wolszon Date: Mon, 23 Oct 2023 16:32:47 +0200 Subject: [PATCH 5/7] Accept only letters in term prefix --- converter/converter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/converter/converter.go b/converter/converter.go index 7d1d608..e5bca34 100644 --- a/converter/converter.go +++ b/converter/converter.go @@ -51,7 +51,7 @@ func (c *Converter) Convert(output io.Writer) error { arb := orderedmap.New[string, any]() arb.Set(localeKey, c.lang) - prefixedRegexp := regexp.MustCompile("(?:(.+):)?(.*)") + prefixedRegexp := regexp.MustCompile("(?:([a-zA-Z]+):)?(.*)") var errs []error for _, term := range jsonContents { From ea5e4a83d25ff6fe7c169019b18f23ff7a3fe1b6 Mon Sep 17 00:00:00 2001 From: Albert Wolszon Date: Tue, 24 Oct 2023 09:59:23 +0200 Subject: [PATCH 6/7] Use debug.BuildInfo for version command --- .goreleaser.yaml | 2 -- cmd/version.go | 59 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 79c0a3e..bef1203 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -8,8 +8,6 @@ builds: - > -s -w -X github.com/leancodepl/poe2arb/cmd.Version={{.Version}} - -X github.com/leancodepl/poe2arb/cmd.Commit={{.Commit}} - -X github.com/leancodepl/poe2arb/cmd.BuiltDate={{.Date}} universal_binaries: - replace: true changelog: diff --git a/cmd/version.go b/cmd/version.go index e65764b..9624ff7 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -1,16 +1,15 @@ package cmd -import "github.com/spf13/cobra" - -var ( - // Version is the version of the application. It is set during the build process using ldflags. - Version = "dev" - // Commit is the commit hash of the application. It is set during the build process using ldflags. - Commit = "none" - // Date is the date of the build. It is set during the build process using ldflags. - BuiltDate = "unknown" +import ( + "errors" + "runtime/debug" + + "github.com/spf13/cobra" ) +// Version is the version of the application. It is set during the build process using ldflags. +var Version string + var versionCmd = &cobra.Command{ Use: "version", Short: "Print the version number of poe2arb", @@ -20,7 +19,47 @@ var versionCmd = &cobra.Command{ func runVersion(cmd *cobra.Command, args []string) error { log := getLogger(cmd) - log.Info("poe2arb version %s, commit %s, built at %s", Version, Commit, BuiltDate) + revision, time, modified, err := getVcsInfo() + if err != nil { + return err + } + + msg := "poe2arb" + if Version != "" { + msg += " version " + Version + } else { + msg += " built from source" + } + + msg += ", commit " + revision + + if modified { + msg += " (with local modifications)" + } + + msg += ", built at " + time + + log.Info(msg) return nil } + +func getVcsInfo() (revision, time string, modified bool, err error) { + info, ok := debug.ReadBuildInfo() + if !ok { + err = errors.New("error reading build info") + return + } + + for _, setting := range info.Settings { + if setting.Key == "vcs.revision" { + revision = setting.Value + } else if setting.Key == "vcs.time" { + time = setting.Value + } else if setting.Key == "vcs.modified" { + modified = setting.Value == "true" + } + } + + return +} From cbe3b72d151ac5315725f7c4165b14ca8f72d455 Mon Sep 17 00:00:00 2001 From: Albert Wolszon Date: Tue, 24 Oct 2023 10:43:05 +0200 Subject: [PATCH 7/7] Fix term-prefix validation --- cmd/poe.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/poe.go b/cmd/poe.go index ad9d9b7..d9b2e7a 100644 --- a/cmd/poe.go +++ b/cmd/poe.go @@ -25,7 +25,7 @@ var ( SilenceUsage: true, RunE: runPoe, } - termPrefixRegexp = regexp.MustCompile("[a-z]*") + termPrefixRegexp = regexp.MustCompile("[a-zA-Z]*") ) const ( @@ -160,8 +160,8 @@ func validatePoeOptions(options *poeOptions) []error { errs = append(errs, errors.New("no POEditor API token provided")) } - if termPrefixRegexp.MatchString(options.TermPrefix) { - errs = append(errs, errors.New("term prefix must contain only lowercase letters or be empty")) + if !termPrefixRegexp.MatchString(options.TermPrefix) { + errs = append(errs, errors.New("term prefix must contain only letters or be empty")) } return errs