Repository navigation
0.7.0-dev: generate Flutter, TypeScript and Python code without flutter gen-l10n - #13
Merged
Merged
Conversation
…en-l10n
`generate` now parses the sheet itself and emits the code directly. It
needs only the Dart SDK: no ARB files, no `flutter gen-l10n`, no Flutter
in CI.
- Dart target: a drop-in replacement for the gen-l10n output (same files,
classes, delegates, lookup and intl plural/select behaviour) plus a
metadata API for tests (scopes, messages, templates, fallback keys,
dynamic format).
- TypeScript target for Astro / SolidJS: zero-dependency ESM, strict
types, lazy per-locale modules, locale negotiation, meta module.
- Python target for backends: zero-dependency, typed, mypy --strict
clean, Accept-Language negotiation.
- Embedded CLDR 48 plural rules so that all targets render plurals
identically; {{name}} mustache placeholders for chosen sheets.
- Validation with sheet/cell locations (ICU syntax, placeholders, plural
categories, tags, duplicates, reserved names, collisions); --strict,
--check and json/github diagnostics.
- sheety.yaml config with per-target output, sheet filters and options.
- Manifest-tracked, staged, deterministic writes that never touch files
the generator does not own, so the output can live inside a package.
BREAKING: ARB-only flags are removed, a real parent locale column wins
over its regional variant, duplicate labels are an error and rows with
missing trailing cells fall back instead of being dropped. See
CHANGELOG.md for the migration notes.
- Share locale column parsing (sanitize, LocaleTag.tryParse, dedupe by
normalized code) between both pipelines; D1 goes through the same path,
so "pt BR" is pt_BR and "Notes" or a second "pt_br" are skipped by
localize as generate skips them. LocaleTag moves to lib/src/common.
- Treat whitespace-only cells as empty everywhere (isBlankCell).
- localize skips rows with an empty source text instead of translating
the label; generate reports empty-base as a warning and leaves the
message out, as its message says.
- localize validates translations with the generate ICU parser (and the
mustache parser for {{name}} sources): unsupported ICU, changed
placeholder kinds and {{x}} -> {x} are rejected; one-word plural and
select branches are no longer mistaken for placeholders.
- localize quotes sheet titles in read ranges (v2, web1 are A1 refs).
- New plural-exact-as-category warning: =0/=1/=2 standing in for a CLDR
category that matches other numbers too (Russian =1 without one).
- Clear error for mustache triple braces.
…l counts intl tests CLDR `n` relations against the count itself, while the core evaluator and the Python runtime used `f == 0`, which only sees three fraction digits: es 1.001 was `one`, ar 1e-7 `zero`, mt 2.0001 `two` (intl and TypeScript: `other`). PluralOperands.intl now keeps the count (`n`) and isIntegral uses it. The Python rules take `(n, i, v, f, t)` and compile `n` relations as `n == i and ...`; intl_operands returns the count first and converts Decimal / Fraction counts with float(), raising TypeError for anything that is not a real number. The Python integration tests now compare with Intl.pluralLogic (all intl locales x fractional counts x branch sets) instead of the core evaluator, and a unit test checks the evaluator against intl.
…at() - Dart scope names only name a directory and <Stem>Localization classes, so default/new/switch/Function are valid again (as in 0.6.0); the TypeScript and Python scope checks keep rejecting their keywords. - localizationArgument accepts any num for a double placeholder and an integral finite num for an int one, so format() behaves the same on the VM and on the web. - templates is documented as the source text of the sheet (ICU, or mustache for mustache sheets). - With the metadata API, locales.dart and the barrel ignore every lint and type the Locale list; gen-l10n mode output is unchanged.
…sing tools - Check out the whole tree in the setup action (dart_test.yaml, .pubignore, LICENSE, example/ and tool/ were missing from the sparse list). - Widen the path filters to everything a check depends on. - Fail the publish dry-run step on a non-zero exit instead of `|| true`, and check the generated example with `generate --check`. - Run all tests in a dedicated integration job with pinned node 22, Python 3.12, mypy 2.4.0 and pyright 1.1.414, SHEETY_REQUIRE_TOOLS=1, and a scan of the JSON report that fails on any skip other than the real-snapshot ones. - Test helpers: SHEETY_REQUIRE_TOOLS=1 turns a missing-tool skip into a failure; pure-Dart PATH lookup instead of `which`; UPDATE_GOLDENS is refused when CI is set; tsc pinned to typescript@5.9.3; a failed npm install of the Solid check fails on CI. - Keep test/golden/ and the CLDR sample table out of the pub archive.
…e reporting - compare target output directories canonically (symlinks, case on case-insensitive file systems) and stage each target in its own .sheety-staging-<target> directory; refuse overlapping plans - report a target left partly written as such in the summary and JSON - never quote a credentials file in errors (no private key excerpt); localize reuses the same reader - an unreadable or non-UTF-8 snapshot is a source-error; unexpected exceptions become an internal-error issue with exit code 2 - usage, config and source errors are printed as JSON / GitHub annotations according to --diagnostics-format - a file looks generated only when it carries the whole header as a comment; taking over an unowned file is a took-over-file warning - keep an edited generated file that is no longer generated (dropped from the manifest); warn when an edited file is overwritten - reject Windows device names in generated paths (reserved-file-name) - remove the unused OutputWriter.skipDirs - GitHub annotations name files relative to the workspace
- source.dart uses the shared sheetRange of lib/src/common. - The barrel exports the localize API and runGenerate only; the tests import the generate internals through test/sheety.dart. - Writer issue paths are absolute, so GitHub annotations point at the file. - Synthetic fixtures no longer reuse names of the production sheet. - Example regenerated; README, CHANGELOG and CLAUDE.md describe the new behaviour.
The CI runs the unit tests as root in the dart container, where a read-only directory does not stop a write. The failures are now caused by a file where the staging directory goes and by a directory swapped for a link out of the output directory after planning, both refused as root too. The CI skip check also allows the case-insensitive file system test, which can only run on macOS.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
generateno longer writes ARB files or runsflutter gen-l10n. It parses the sheet, validates it and emits the code itself, so generating needs only the Dart SDK and CI no longer downloads Flutter.Targets (each sheet is still its own scope, every target has its own sheet filter):
of(context), delegates,supportedLocales,intlplural/select). It adds a metadata API for tests:localizationScopes,messages(key, description, placeholders), per-localetemplates/fallbackKeysandformat(key, args).metadata: falseturns the API off.loaders,resolveLocale, an eager bundle for SSR and ametamodule.mypy --strictclean. Typed snake_case accessors,get()withAccept-Languagenegotiation,format(key, **args).Shared behaviour:
{{name}}(mustache) placeholders for chosen sheets.--strict,--checkand--diagnostics-format=json|github.sheety.yamlconfig.Breaking changes and migration notes are in
CHANGELOG.md(0.7.0-dev).The old
example/held real sheet data. It is replaced by a synthetic example covering all three targets.Verification
dart format,dart analyze --fatal-infos --fatal-warnings: clean.dart test: green. Integration tests runflutter analyze/flutter test,tsc --strict+ node, Python + mypy + pyright.--check: up to date.dart pub publish --dry-run: no errors.SHEETY_REAL_SNAPSHOT/SHEETY_REAL_REFERENCE):flutter analyzeclean, and itstool/version.dartcomputes a patch bump.