Skip to content

Add poe2arb upload for syncing local ARB changes with POEditor#96

Open
Albert221 wants to merge 3 commits into
mainfrom
claude/add-poe2arb-upload-VKGRW
Open

Add poe2arb upload for syncing local ARB changes with POEditor#96
Albert221 wants to merge 3 commits into
mainfrom
claude/add-poe2arb-upload-VKGRW

Conversation

@Albert221
Copy link
Copy Markdown
Member

Summary

Adds a new poe2arb upload subcommand that synchronizes local ARB file changes back to POEditor. Unlike seed (which is meant for one-shot first-time imports and deliberately never overwrites), upload is intended for the day-to-day workflow of pushing local ARB edits to POEditor — including changes to terms that already exist remotely.

Behavior

  1. Lists project terms via /terms/list (asking for the template language so we can show translations as a preview).
  2. Compares them with the terms in the local template ARB file.
  3. If any terms exist remotely but not locally, the command prints the orphan terms (with their template-language values when available) and aborts:
    • the following 2 term(s) exist in POEditor but not in local ARB files:
      • - obsoleteTerm = "no longer used"
      • - anotherOldOne
    • aborting. Re-run with --force to delete these terms from POEditor and continue the upload.
    
    Re-running with --force deletes them via /terms/delete and proceeds.
  4. Adds missing project languages (same as seed).
  5. Uploads each ARB to POEditor with overwrite=1, template language first so term definitions get registered before non-template translations come in. Same paid/free rate-limit handling as seed.

Design notes

  • Term deletion uses /terms/delete with an explicit list rather than the upload endpoint's sync_terms=1. The latter deletes every term in the project that's not in the upload, which would silently wipe terms belonging to other prefixes (sibling packages in a multi-package POE project). The explicit-list approach respects the existing --term-prefix scoping: termInPrefixScope only flags remote terms whose prefix matches the local one for deletion.
  • The fuzzy-trigger flag is intentionally not sent — translations get overwritten as-is without disturbing fuzzy state.
  • The existing Client.Upload signature was extended to take an UploadOptions{Overwrite} struct; seed uses the zero value, preserving its non-destructive default.

Tests

  • New poeditor/client_test.go covers ListTerms (with translation parsing for both string and plural-object content forms), DeleteTerms (incl. empty-input no-op), Upload (overwrite=0/overwrite=1/rate-limit error propagation), GetProjectLanguages, and AddLanguage against an httptest.Server mock.
  • New cmd/upload_test.go covers the prefix-scope diff logic (termInPrefixScope, termsToDelete), template-ARB term parsing (readLocalTermNames), and ARB-file discovery / template ordering helpers.

Test plan

  • go build ./...
  • go test ./...
  • go tool staticcheck -checks=all ./...
  • go tool gofumpt -d clean
  • Manual smoke test against a real POE project — run poe2arb upload (expect abort listing orphan terms), then poe2arb upload --force (expect deletion + overwriting upload).

README

Adds a new "Synchronizing local ARB changes with POEditor" section under Usage, documenting the workflow, the --force flag, and the prefix-scope safety guarantee.


Generated by Claude Code

claude added 3 commits May 8, 2026 11:41
Unlike `seed`, `upload` is meant for keeping POEditor in sync with ongoing
local ARB edits. It overwrites existing translations and term definitions,
adds new terms and missing languages.

Before uploading, the command lists project terms and compares them with
the local template ARB. If any orphaned remote terms are found, the upload
aborts and prints them; passing `--force` deletes them via /terms/delete
and proceeds. Term-prefix scope is respected so sibling packages sharing
one POEditor project are unaffected.

The deletion step uses /terms/delete with a per-term list rather than the
upload endpoint's `sync_terms` flag, which would otherwise wipe terms
belonging to other prefixes in the same project.
…upload

`poe2arb upload --dry-run` now reports:
- terms to be added (in local but not in POEditor)
- terms to be removed (in POEditor but not local; need --force)
- per-language summary of how many translations would be added,
  updated, or are unchanged, plus whether each language would be
  created in the POEditor project

It performs one /terms/list call per language to compare local vs.
remote translations exactly. No mutating endpoints are called.

A new GitHub Actions job `write-integration-test` exercises seed and
upload end-to-end against a dedicated POEditor project. It:

1. Seeds an empty project from stage1 fixtures and verifies via
   `upload --dry-run` that the state is consistent (zero changes).
2. Modifies ARBs (adds + updates terms), checks the dry-run output,
   uploads, then re-checks with dry-run.
3. Removes a term, verifies the dry-run flags it for deletion, asserts
   that `upload` without --force aborts non-zero, then `upload --force`
   succeeds; finally re-downloads via `poe poe` and confirms the term
   is gone.

The job is gated on `vars.POEDITOR_INTEGRATION_TESTS_WRITE_PROJECT_ID`
so it skips on forks and contributor PRs lacking the test-project
configuration. It uses a `concurrency` group to prevent concurrent
runs from racing on the shared test project.
Both jobs hit the same rate-limited POEditor account. Share a single
`poeditor-integration` concurrency group so the read-only and write
jobs never run in parallel.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants