From 719bb2123cfa3c9d10cd1c3e4a17d12ffe26a13d Mon Sep 17 00:00:00 2001 From: Ralf Haferkamp Date: Wed, 27 May 2026 10:14:11 +0200 Subject: [PATCH] fix: translations for activities and others This fixes the server-side translations for "activties" and e.g. the default space description. We need to bump "leonelquinteros/gotext" to latest master for that as even the latest release still contains and issue that cause `go vet` to complain about non-constant format strings. Fixes: #2833, #2835 --- go.mod | 2 +- go.sum | 4 +- pkg/l10n/l10n.go | 2 +- .../expected-failures-decomposed-storage.md | 4 - .../expected-failures-posix-storage.md | 4 - .../leonelquinteros/gotext/GEMINI.md | 49 +++ .../leonelquinteros/gotext/README.md | 304 ++++++------------ .../leonelquinteros/gotext/gotext.go | 2 +- .../leonelquinteros/gotext/helper.go | 7 +- .../leonelquinteros/gotext/locale.go | 8 +- .../leonelquinteros/gotext/mkdocs.yml | 39 +++ .../gotext/plurals/compiler.go | 61 ++-- vendor/modules.txt | 4 +- 13 files changed, 242 insertions(+), 248 deletions(-) create mode 100644 vendor/github.com/leonelquinteros/gotext/GEMINI.md create mode 100644 vendor/github.com/leonelquinteros/gotext/mkdocs.yml diff --git a/go.mod b/go.mod index 85477ddedc..652154b5fd 100644 --- a/go.mod +++ b/go.mod @@ -49,7 +49,7 @@ require ( github.com/jinzhu/now v1.1.5 github.com/justinas/alice v1.2.0 github.com/kovidgoyal/imaging v1.8.20 - github.com/leonelquinteros/gotext v1.7.2 + github.com/leonelquinteros/gotext v1.7.3-0.20260422134830-b012b4ccae69 github.com/libregraph/idm v0.5.0 github.com/libregraph/lico v0.66.0 github.com/mitchellh/mapstructure v1.5.0 diff --git a/go.sum b/go.sum index 4d94febb7e..821e6d843b 100644 --- a/go.sum +++ b/go.sum @@ -756,8 +756,8 @@ github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvf github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/leonelquinteros/gotext v1.7.2 h1:bDPndU8nt+/kRo1m4l/1OXiiy2v7Z7dfPQ9+YP7G1Mc= -github.com/leonelquinteros/gotext v1.7.2/go.mod h1:9/haCkm5P7Jay1sxKDGJ5WIg4zkz8oZKw4ekNpALob8= +github.com/leonelquinteros/gotext v1.7.3-0.20260422134830-b012b4ccae69 h1:ZLo0bXX17iUZpb/Sp7N+1uK4Jb7dl0fm5x5ETfzYSvY= +github.com/leonelquinteros/gotext v1.7.3-0.20260422134830-b012b4ccae69/go.mod h1:ksG5iXViKefoupjy+0qQjAVoaDnylnQ1ejWl9g14wh8= github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA= github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw= github.com/lestrrat-go/dsig v1.0.0 h1:OE09s2r9Z81kxzJYRn07TFM9XA4akrUdoMwr0L8xj38= diff --git a/pkg/l10n/l10n.go b/pkg/l10n/l10n.go index d9ef549db2..a7c657a788 100644 --- a/pkg/l10n/l10n.go +++ b/pkg/l10n/l10n.go @@ -54,7 +54,7 @@ func NewTranslatorFromCommonConfig(defaultLocale string, domain string, path str // Translate translates a string to the locale func (t Translator) Translate(str, locale string) string { - return t.Locale(locale).Get("%s", str) + return t.Locale(locale).Get(str) } // Locale returns the gotext.Locale, use `.Get` method to translate strings diff --git a/tests/acceptance/expected-failures-decomposed-storage.md b/tests/acceptance/expected-failures-decomposed-storage.md index 9e8b56b330..1223612890 100644 --- a/tests/acceptance/expected-failures-decomposed-storage.md +++ b/tests/acceptance/expected-failures-decomposed-storage.md @@ -190,10 +190,6 @@ - [apiServiceAvailability/serviceAvailabilityCheck.feature:123](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiServiceAvailability/serviceAvailabilityCheck.feature#L123) -#### [Skip tests for different languages](https://github.com/opencloud-eu/opencloud/issues/183) - -- [apiActivities/activities.feature:2598](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiActivities/activities.feature#L2598) - #### [Missing properties in REPORT response](https://github.com/owncloud/ocis/issues/9780), [d:getetag property has empty value in REPORT response](https://github.com/owncloud/ocis/issues/9783) - [apiSearch1/search.feature:437](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiSearch1/search.feature#L437) diff --git a/tests/acceptance/expected-failures-posix-storage.md b/tests/acceptance/expected-failures-posix-storage.md index 971ded304a..58b9f74e5c 100644 --- a/tests/acceptance/expected-failures-posix-storage.md +++ b/tests/acceptance/expected-failures-posix-storage.md @@ -190,10 +190,6 @@ - [apiServiceAvailability/serviceAvailabilityCheck.feature:123](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiServiceAvailability/serviceAvailabilityCheck.feature#L123) -#### [Skip tests for different languages](https://github.com/opencloud-eu/opencloud/issues/183) - -- [apiActivities/activities.feature:2598](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiActivities/activities.feature#L2598) - #### [Missing properties in REPORT response](https://github.com/owncloud/ocis/issues/9780), [d:getetag property has empty value in REPORT response](https://github.com/owncloud/ocis/issues/9783) - [apiSearch1/search.feature:437](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/apiSearch1/search.feature#L437) diff --git a/vendor/github.com/leonelquinteros/gotext/GEMINI.md b/vendor/github.com/leonelquinteros/gotext/GEMINI.md new file mode 100644 index 0000000000..a3c383234d --- /dev/null +++ b/vendor/github.com/leonelquinteros/gotext/GEMINI.md @@ -0,0 +1,49 @@ +# GEMINI.md - gotext Project Context & Guidelines + +This document serves as the primary source of truth for the `gotext` project architecture, conventions, and workflows. Adherence to these guidelines is mandatory for all development tasks. + +## Project Overview +`gotext` is a GNU Gettext implementation for Go (Golang). it provides a thread-safe, hierarchical translation system that supports PO/MO files, plural forms, and context-aware translations. + +## Core Architecture +The project follows a hierarchical structure for managing translations: +1. **Global Package API (`gotext.go`)**: Provides convenient, global functions (e.g., `Get`, `GetD`, `GetN`) that rely on a shared `globalConfig`. +2. **Locales (`locale.go`)**: Represent a specific language (e.g., "en_US", "es_ES"). A `Locale` container manages multiple `Domains`. +3. **Domains (`domain.go`)**: The core translation engine for a specific set of messages. It handles: + - Message retrieval (with support for plural forms and `msgctxt`). + - Header parsing (including plural-form rules). + - Thread-safety via `sync.RWMutex`. +4. **Translators (`translator.go`)**: An interface for translation sources. + - **PO (`po.go`)**: Parsers for human-readable Gettext Portable Object files. + - **MO (`mo.go`)**: Parsers for binary Gettext Machine Object files. +5. **Plural Forms (`plurals/`)**: A dedicated package for compiling and evaluating GNU Gettext plural form expressions. + +## CLI Tools +- **xgotext (`cli/xgotext/`)**: A tool to scan Go source files, extract translatable strings (matching `Get`, `GetD`, etc.), and generate/update PO files. + +## Development Workflows +### Branching & PRs +- **Feature Branches**: All development MUST happen in dedicated feature branches (e.g., `feature/description-of-change`). +- **Target Branch**: All Pull Requests MUST be made against the `master` branch. +- **Review Requirement**: No direct commits to `master` are allowed. All changes must be reviewed via a PR. +- **GitHub Integration**: If the `gh` CLI tool is installed and authenticated, it should be used for managing Pull Requests, Issues, and Reviews. Otherwise, these tasks must be performed manually through the GitHub web interface. + +### Coding Standards +- **Idiomatic Go**: Follow standard Go conventions (`gofmt`, `go vet`). +- **Thread Safety**: Ensure all shared state (like in `Domain`) is protected by appropriate synchronization primitives. +- **Testing**: + - Every new feature or bug fix must include corresponding tests. + - Use the `fixtures/` directory for sample PO/MO files. + - Run `go test ./...` to ensure no regressions. + +## Key Files & Symbols +- `gotext.go`: `Configure`, `Get`, `GetD`, `GetN`. +- `locale.go`: `Locale`, `NewLocale`, `AddDomain`. +- `domain.go`: `Domain`, `Get`, `GetN`, `parseHeaders`. +- `translator.go`: `Translator` interface. +- `plurals/compiler.go`: `Compile` function for plural expressions. + +## Instructions for Gemini CLI +- Always work in a feature branch. +- Before submitting, verify changes with existing and new tests. +- Propose a PR to `master` after confirmation. diff --git a/vendor/github.com/leonelquinteros/gotext/README.md b/vendor/github.com/leonelquinteros/gotext/README.md index c8ee2ace79..0b7e0e8452 100644 --- a/vendor/github.com/leonelquinteros/gotext/README.md +++ b/vendor/github.com/leonelquinteros/gotext/README.md @@ -9,258 +9,142 @@ [GNU gettext utilities](https://www.gnu.org/software/gettext) for Go. +`gotext` is a native Go implementation of the GNU Gettext utilities. It provides a thread-safe, flexible, and powerful way to handle internationalization (i18n) and localization (l10n) in your Go applications. -# Features +--- -- Implements GNU gettext support in native Go. -- Complete support for [PO files](https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html) including: - - Support for multiline strings and headers. - - Support for variables inside translation strings using Go's [fmt syntax](https://golang.org/pkg/fmt/). - - Support for [pluralization rules](https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html). - - Support for [message contexts](https://www.gnu.org/software/gettext/manual/html_node/Contexts.html). -- Support for MO files. -- Thread-safe: This package is safe for concurrent use across multiple goroutines. -- It works with UTF-8 encoding as it's the default for Go language. -- Unit tests available. -- Language codes are automatically simplified from the form `en_UK` to `en` if the first isn't available. -- Ready to use inside Go templates. -- Objects are serializable to []byte to store them in cache. -- Support for Go Modules. +**📖 [Read the Full Documentation](https://leonelquinteros.github.io/gotext/)** +--- -# License +### Table of Contents +- [Features](#features) +- [Installation](#installation) +- [Getting Started](#getting-started) +- [CLI Tool (xgotext)](#cli-tool-xgotext) +- [Advanced Usage](#advanced-usage) + - [Locale Object](#using-locale-object) + - [Plural Forms](#use-plural-forms-of-translations) + - [Dynamic Variables](#using-dynamic-variables-on-translations) +- [Directory Structure](#locales-directories-structure) +- [Contributing](#contributing) +- [License](#license) -[MIT license](LICENSE) +--- +## Features +- Native Go implementation of Gettext (no external dependencies). +- Full support for **PO and MO files**. +- **Pluralization rules** support via GNU Gettext plural-form expressions. +- **Message context** support (`msgctxt`). +- Thread-safe for concurrent use. +- Works with UTF-8 by default. +- Integrated CLI tool (`xgotext`) for string extraction. +- Serializable objects for caching. +- Seamless integration with Go's `text/template` and `html/template`. -# Documentation +--- -Refer to package documentation at (https://pkg.go.dev/github.com/leonelquinteros/gotext) - - -# Installation - -``` +## Installation +```bash go get github.com/leonelquinteros/gotext ``` -- There are no requirements or dependencies to use this package. -- No need to install GNU gettext utilities (unless specific needs of CLI tools). -- No need for environment variables. Some naming conventions are applied but not needed. +--- - -# Usage examples - -## Using package for single language/domain settings - -For quick/simple translations you can use the package level functions directly. +## Getting Started +For a quick start, use the package-level API: ```go +package main + import ( "fmt" "github.com/leonelquinteros/gotext" ) func main() { - // Configure package - gotext.Configure("/path/to/locales/root/dir", "en_UK", "domain-name") + // Configure package: locales path, language, and domain + gotext.Configure("/path/to/locales", "en_US", "default") - // Translate text from default domain - fmt.Println(gotext.Get("My text on 'domain-name' domain")) + // Simple translation + fmt.Println(gotext.Get("Hello, world!")) - // Translate text from a different domain without reconfigure - fmt.Println(gotext.GetD("domain2", "Another text on a different domain")) + // Translation with variables + fmt.Println(gotext.Get("Hello, %s!", "Gopher")) } - ``` -## Using dynamic variables on translations +For more details, see the [Getting Started Guide](docs/GETTING_STARTED.md). -All translation strings support dynamic variables to be inserted without translate. -Use the fmt.Printf syntax (from Go's "fmt" package) to specify how to print the non-translated variable inside the translation string. +--- + +## CLI Tool (xgotext) +`gotext` includes a command-line tool to extract translatable strings from your Go source code. + +**Install xgotext:** +```bash +go install github.com/leonelquinteros/gotext/cli/xgotext@latest +``` + +**Extract strings:** +```bash +xgotext -p . -o locales/en_US/default.po +``` + +See the [xgotext Documentation](docs/xgotext.md) for full usage details. + +--- + +## Advanced Usage + +### Using Locale object +For managing multiple languages or domains independently: ```go -import ( - "fmt" - "github.com/leonelquinteros/gotext" -) - -func main() { - // Configure package - gotext.Configure("/path/to/locales/root/dir", "en_UK", "domain-name") - - // Set variables - name := "John" - - // Translate text with variables - fmt.Println(gotext.Get("Hi, my name is %s", name)) -} - +l := gotext.NewLocale("/path/to/locales", "es_UY") +l.AddDomain("default") +fmt.Println(l.Get("Translate this")) ``` - -## Using Locale object - -When having multiple languages/domains/libraries at the same time, you can create Locale objects for each variation -so you can handle each settings on their own. +### Use plural forms of translations +`gotext` handles complex pluralization rules defined in PO headers: ```go -import ( - "fmt" - "github.com/leonelquinteros/gotext" -) - -func main() { - // Create Locale with library path and language code - l := gotext.NewLocale("/path/to/locales/root/dir", "es_UY") - - // Load domain '/path/to/locales/root/dir/es_UY/default.po' - l.AddDomain("default") - - // Translate text from default domain - fmt.Println(l.Get("Translate this")) - - // Load different domain - l.AddDomain("translations") - - // Translate text from domain - fmt.Println(l.GetD("translations", "Translate this")) -} +// GetN(singular, plural, quantity, args...) +fmt.Println(gotext.GetN("I have one apple.", "I have %d apples.", 5, 5)) ``` +See the [Plural Forms Guide](docs/PLURALS.md) for more examples. -This is also helpful for using inside templates (from the "text/template" package), where you can pass the Locale object to the template. -If you set the Locale object as "Loc" in the template, then the template code would look like: - -``` -{{ .Loc.Get "Translate this" }} -``` - - -## Using the Po object to handle .po files and PO-formatted strings - -For when you need to work with PO files and strings, -you can directly use the Po object to parse it and access the translations in there in the same way. - +### Using dynamic variables on translations +Supports standard `fmt` package syntax: ```go -import ( - "fmt" - "github.com/leonelquinteros/gotext" -) - -func main() { - // Set PO content - str := ` -msgid "Translate this" -msgstr "Translated text" - -msgid "Another string" -msgstr "" - -msgid "One with var: %s" -msgstr "This one sets the var: %s" -` - - // Create Po object - po := gotext.NewPo() - po.Parse(str) - - fmt.Println(po.Get("Translate this")) -} +name := "John" +fmt.Println(gotext.Get("Hi, my name is %s", name)) ``` +--- -## Use plural forms of translations - -PO format supports defining one or more plural forms for the same translation. -Relying on the PO file headers, a Plural-Forms formula can be set on the translation file -as defined in (https://www.gnu.org/savannah-checkouts/gnu/gettext/manual/html_node/Plural-forms.html) - -```go -import ( - "fmt" - "github.com/leonelquinteros/gotext" -) - -func main() { - // Set PO content - str := ` -msgid "" -msgstr "" - -# Header below -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -msgid "Translate this" -msgstr "Translated text" - -msgid "Another string" -msgstr "" - -msgid "One with var: %s" -msgid_plural "Several with vars: %s" -msgstr[0] "This one is the singular: %s" -msgstr[1] "This one is the plural: %s" -` - - // Create Po object - po := new(gotext.Po) - po.Parse(str) - - fmt.Println(po.GetN("One with var: %s", "Several with vars: %s", 54, v)) - // "This one is the plural: Variable" -} -``` - - -# Locales directories structure - -The package will assume a directories structure starting with a base path that will be provided to the package configuration -or to object constructors depending on the use, but either will use the same convention to lookup inside the base path. - -Inside the base directory where will be the language directories named using the language and country 2-letter codes (en_US, es_AR, ...). -All package functions can lookup after the simplified version for each language in case the full code isn't present but the more general language code exists. -So if the language set is `en_UK`, but there is no directory named after that code and there is a directory named `en`, -all package functions will be able to resolve this generalization and provide translations for the more general library. - -The language codes are assumed to be [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) codes (2-letter codes). -That said, most functions will work with any coding standard as long the directory name matches the language code set on the configuration. - -Then, there can be a `LC_MESSAGES` containing all PO files or the PO files themselves. -A library directory structure can look like: - +## Locales directories structure +The package expects a standard Gettext directory structure: ``` /path/to/locales -/path/to/locales/en_US -/path/to/locales/en_US/LC_MESSAGES -/path/to/locales/en_US/LC_MESSAGES/default.po -/path/to/locales/en_US/LC_MESSAGES/extras.po -/path/to/locales/en_UK -/path/to/locales/en_UK/LC_MESSAGES -/path/to/locales/en_UK/LC_MESSAGES/default.po -/path/to/locales/en_UK/LC_MESSAGES/extras.po -/path/to/locales/en_AU -/path/to/locales/en_AU/LC_MESSAGES -/path/to/locales/en_AU/LC_MESSAGES/default.po -/path/to/locales/en_AU/LC_MESSAGES/extras.po -/path/to/locales/es -/path/to/locales/es/default.po -/path/to/locales/es/extras.po -/path/to/locales/es_ES -/path/to/locales/es_ES/default.po -/path/to/locales/es_ES/extras.po -/path/to/locales/fr -/path/to/locales/fr/default.po -/path/to/locales/fr/extras.po + /en_US + /LC_MESSAGES + default.po + /es_ES + default.po ``` +It supports automatic language simplification (e.g., falling back from `en_UK` to `en`). -And so on... +--- +## Contributing +We welcome contributions of all kinds! +- [Contributing Guidelines](CONTRIBUTING.md) +- [Code of Conduct](CODE_OF_CONDUCT.md) -# Contribute - -- Please, contribute. -- Use the package on your projects. -- Report issues on Github. -- Send pull requests for bugfixes and improvements. -- Send proposals on Github issues. +--- +## License +`gotext` is released under the [MIT License](LICENSE). diff --git a/vendor/github.com/leonelquinteros/gotext/gotext.go b/vendor/github.com/leonelquinteros/gotext/gotext.go index b8cb30ce51..059403c34d 100644 --- a/vendor/github.com/leonelquinteros/gotext/gotext.go +++ b/vendor/github.com/leonelquinteros/gotext/gotext.go @@ -55,7 +55,7 @@ func init() { domain: "default", languages: []string{FallbackLocale}, library: "/usr/local/share/locale", - locales: nil, + locales: make([]*Locale, 0), } // Register Translator types for gob encoding diff --git a/vendor/github.com/leonelquinteros/gotext/helper.go b/vendor/github.com/leonelquinteros/gotext/helper.go index 91ea255d40..1e6a610f45 100644 --- a/vendor/github.com/leonelquinteros/gotext/helper.go +++ b/vendor/github.com/leonelquinteros/gotext/helper.go @@ -31,12 +31,17 @@ func SimplifiedLocale(lang string) string { // FormatString applies text formatting only when needed to parse variables. func FormatString(str string, vars ...interface{}) string { if len(vars) > 0 { - return fmt.Sprintf(str, vars...) + return FormatStringWithArgs(str, vars) } return str } +// FormatStringWithArgs applies text formatting as a proxy for fmt.Sprintf. +func FormatStringWithArgs(str string, vars []interface{}) string { + return fmt.Sprintf(str, vars...) +} + // Appendf applies text formatting only when needed to parse variables. func Appendf(b []byte, str string, vars ...interface{}) []byte { if len(vars) > 0 { diff --git a/vendor/github.com/leonelquinteros/gotext/locale.go b/vendor/github.com/leonelquinteros/gotext/locale.go index 7295c31338..381e5602ab 100644 --- a/vendor/github.com/leonelquinteros/gotext/locale.go +++ b/vendor/github.com/leonelquinteros/gotext/locale.go @@ -357,7 +357,7 @@ func (l *Locale) GetTranslations() map[string]*Translation { // IsTranslated reports whether a string is translated func (l *Locale) IsTranslated(str string) bool { - return l.IsTranslatedND(l.GetDomain(), str, 0) + return l.IsTranslatedND(l.GetDomain(), str, 1) } // IsTranslatedN reports whether a plural string is translated @@ -367,7 +367,7 @@ func (l *Locale) IsTranslatedN(str string, n int) bool { // IsTranslatedD reports whether a domain string is translated func (l *Locale) IsTranslatedD(dom, str string) bool { - return l.IsTranslatedND(dom, str, 0) + return l.IsTranslatedND(dom, str, 1) } // IsTranslatedND reports whether a plural domain string is translated @@ -387,7 +387,7 @@ func (l *Locale) IsTranslatedND(dom, str string, n int) bool { // IsTranslatedC reports whether a context string is translated func (l *Locale) IsTranslatedC(str, ctx string) bool { - return l.IsTranslatedNDC(l.GetDomain(), str, 0, ctx) + return l.IsTranslatedNDC(l.GetDomain(), str, 1, ctx) } // IsTranslatedNC reports whether a plural context string is translated @@ -397,7 +397,7 @@ func (l *Locale) IsTranslatedNC(str string, n int, ctx string) bool { // IsTranslatedDC reports whether a domain context string is translated func (l *Locale) IsTranslatedDC(dom, str, ctx string) bool { - return l.IsTranslatedNDC(dom, str, 0, ctx) + return l.IsTranslatedNDC(dom, str, 1, ctx) } // IsTranslatedNDC reports whether a plural domain context string is translated diff --git a/vendor/github.com/leonelquinteros/gotext/mkdocs.yml b/vendor/github.com/leonelquinteros/gotext/mkdocs.yml new file mode 100644 index 0000000000..f0ad3421aa --- /dev/null +++ b/vendor/github.com/leonelquinteros/gotext/mkdocs.yml @@ -0,0 +1,39 @@ +site_name: gotext +site_description: GNU gettext utilities for Go +site_author: Leonel Quinteros +repo_url: https://github.com/leonelquinteros/gotext +edit_uri: edit/master/docs/ + +theme: + name: material + palette: + primary: indigo + accent: indigo + features: + - navigation.tabs + - navigation.sections + - navigation.top + - search.suggest + - search.highlight + +nav: + - Home: index.md + - Getting Started: GETTING_STARTED.md + - User Guides: + - Plural Forms: PLURALS.md + - xgotext CLI: xgotext.md + - Character Encoding: ENCODING.md + - Best Practices: BEST_PRACTICES.md + - API Reference: https://pkg.go.dev/github.com/leonelquinteros/gotext + - Contributing: + - Guidelines: CONTRIBUTING.md + - Code of Conduct: CODE_OF_CONDUCT.md + - License: LICENSE.md + +markdown_extensions: + - admonition + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.superfences diff --git a/vendor/github.com/leonelquinteros/gotext/plurals/compiler.go b/vendor/github.com/leonelquinteros/gotext/plurals/compiler.go index 01cd067ae1..c28297a5da 100644 --- a/vendor/github.com/leonelquinteros/gotext/plurals/compiler.go +++ b/vendor/github.com/leonelquinteros/gotext/plurals/compiler.go @@ -22,7 +22,7 @@ type match struct { closePos int } -var pat = regexp.MustCompile(`(\?|:|\|\||&&|==|!=|>=|>|<=|<|%|\d+|n)`) +var pat = regexp.MustCompile(`(\?|:|\|\||&&|==|!=|>=|>|<=|<|%|\d+|n|\(|\))`) type testToken interface { compile(tokens []string) (test test, err error) @@ -161,29 +161,28 @@ func compileEquality(tokens []string, sep string, builder cmpTestBuilder) (test if err != nil { return test, err } - if len(split.Left) == 1 && split.Left[0] == "n" { - if len(split.Right) != 1 { - return test, errors.New("test can only compare n to integers") - } - i, err := parseUint32(split.Right[0]) + if contains(split.Left, "n") && !contains(split.Left, "%") && len(split.Left) == 1 { + i, err := parseUint32(strings.Join(split.Right, "")) if err != nil { + // Try to compile it as a full expression if it's not a simple integer + // but for now we follow the existing pattern of expecting integers here + // unless it's a mod operation. return test, err } return builder(i, false), nil - } else if len(split.Right) == 1 && split.Right[0] == "n" { - if len(split.Left) != 1 { - return test, errors.New("test can only compare n to integers") - } - i, err := parseUint32(split.Left[0]) + } else if contains(split.Right, "n") && !contains(split.Right, "%") && len(split.Right) == 1 { + i, err := parseUint32(strings.Join(split.Left, "")) if err != nil { return test, err } return builder(i, true), nil } else if contains(split.Left, "n") && contains(split.Left, "%") { return subPipe(split.Left, split.Right, builder, false) + } else if contains(split.Right, "n") && contains(split.Right, "%") { + return subPipe(split.Right, split.Left, builder, true) } - return test, errors.New("equality test must have 'n' as one of the two tests") + return test, errors.New("equality test must have 'n' as one of the two tests") } var eqToken eqStruct @@ -353,7 +352,7 @@ func split(s string) <-chan string { // Tokenizes a string into a list of strings, tokens grouped by parenthesis are // not split! If the string starts with ( and ends in ), those are stripped. -func tokenize(s string) []string { +func tokenize(s string) ([]string, error) { /* TODO: Properly detect if the string starts with a ( and ends with a ) and that those two form a matching pair. @@ -361,7 +360,7 @@ func tokenize(s string) []string { Eg: (foo) -> true; (foo)(bar) -> false; */ if len(s) == 0 { - return []string{} + return []string{}, nil } if s[0] == '(' && s[len(s)-1] == ')' { s = s[1 : len(s)-1] @@ -372,15 +371,22 @@ func tokenize(s string) []string { if chunk[0] == '(' && chunk[len(chunk)-1] == ')' { ret = append(ret, chunk) } else { - for _, token := range pat.FindAllStringSubmatch(chunk, -1) { + // Verify all characters in chunk are matched by our pattern + matches := pat.FindAllStringSubmatch(chunk, -1) + matchedLen := 0 + for _, token := range matches { ret = append(ret, token[0]) + matchedLen += len(token[0]) + } + if matchedLen != len(chunk) { + return nil, fmt.Errorf("invalid character in expression chunk: %s", chunk) } } } else { fmt.Printf("Empty chunk in string '%s'\n", s) } } - return ret + return ret, nil } // Compile a string containing a plural form expression to a Expression object. @@ -406,7 +412,10 @@ func contains(haystack []string, needle string) bool { // Compiles an expression (ternary or constant) func compileExpression(s string) (expr Expression, err error) { - tokens := tokenize(s) + tokens, err := tokenize(s) + if err != nil { + return nil, err + } if contains(tokens, "?") { return ternaryToken.compile(tokens) } @@ -415,12 +424,28 @@ func compileExpression(s string) (expr Expression, err error) { // Compiles a test (comparison) func compileTest(s string) (test test, err error) { - tokens := tokenize(s) + tokens, err := tokenize(s) + if err != nil { + return nil, err + } for _, tokenDef := range precedence { if contains(tokens, tokenDef.op) { return tokenDef.token.compile(tokens) } } + if contains(tokens, "%") { + m, err := compileMod(tokens) + if err != nil { + return nil, err + } + return pipe{ + modifier: m, + action: equal{value: 0}, // default to testing for 0 + }, nil + } + if len(tokens) == 1 && tokens[0] == "n" { + return equal{value: 1}, nil + } return test, errors.New("cannot compile") } diff --git a/vendor/modules.txt b/vendor/modules.txt index c2ea5e9969..c57fa7fd44 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -898,8 +898,8 @@ github.com/kovidgoyal/imaging/webp ## explicit; go 1.18 github.com/leodido/go-urn github.com/leodido/go-urn/scim/schema -# github.com/leonelquinteros/gotext v1.7.2 -## explicit; go 1.23.5 +# github.com/leonelquinteros/gotext v1.7.3-0.20260422134830-b012b4ccae69 +## explicit; go 1.25 github.com/leonelquinteros/gotext github.com/leonelquinteros/gotext/plurals # github.com/lestrrat-go/blackmagic v1.0.4