-
Notifications
You must be signed in to change notification settings - Fork 24
chore(i18n): add Cursor Memsource skill and peer usage guide #272
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
097f986
e2559dd
99c0f3b
fc15194
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,383 @@ | ||||||||||||||||||
| --- | ||||||||||||||||||
| name: i18n-memsource | ||||||||||||||||||
| description: >- | ||||||||||||||||||
| Automates the Memsource/Phrase i18n translation workflow for nmstate-console-plugin. | ||||||||||||||||||
| Use when the user asks to upload translations, download translations, check translation | ||||||||||||||||||
| status, memsource upload, memsource download, i18n upload, i18n download, send for | ||||||||||||||||||
| translation, or get translations. | ||||||||||||||||||
| --- | ||||||||||||||||||
|
|
||||||||||||||||||
| # nmstate-console-plugin i18n Memsource Workflow | ||||||||||||||||||
|
|
||||||||||||||||||
| Manages upload/download of translations to Phrase (Memsource) for this repo. | ||||||||||||||||||
|
|
||||||||||||||||||
| Uses the **existing** local `i18n-scripts/` + `i18next-parser` setup. | ||||||||||||||||||
| Does **not** use `ocp-plugin-i18n-scripts` or `i18next-cli`. | ||||||||||||||||||
|
|
||||||||||||||||||
| For a peer-oriented walkthrough, see [USAGE.md](./USAGE.md). | ||||||||||||||||||
|
|
||||||||||||||||||
| ## State | ||||||||||||||||||
|
|
||||||||||||||||||
| Read and update `.cursor/skills/i18n-memsource/state.json` after each upload. | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Plugin config | ||||||||||||||||||
|
|
||||||||||||||||||
| | Field | Value | | ||||||||||||||||||
| |-------|-------| | ||||||||||||||||||
| | Namespace / locale file | `plugin__nmstate-console-plugin` | | ||||||||||||||||||
| | Memsource template ID | `zBOwr4BxYwEq7xlJ37c1F3` | | ||||||||||||||||||
| | Project title | `[OCP $VERSION] UI Localization nmstate-console-plugin - Sprint $SPRINT/Branch $BRANCH` | | ||||||||||||||||||
| | Languages | `ja`, `zh-cn`, `ko`, `fr`, `es` | | ||||||||||||||||||
| | Locale dirs on disk | `en`, `es`, `fr`, `ja`, `ko`, **`zh`** (not `zh-cn`) | | ||||||||||||||||||
| | PO filename pattern | `po-files/<lang>/plugin__nmstate-console-plugin.po` | | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Prerequisites | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Memsource CLI | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| MEMSOURCE_BIN=$(python3 -c "import shutil; print(shutil.which('memsource') or '')") | ||||||||||||||||||
| if [ -z "$MEMSOURCE_BIN" ]; then | ||||||||||||||||||
| MEMSOURCE_BIN=$(find "$HOME/Library/Python" -name memsource -type f 2>/dev/null | head -1) | ||||||||||||||||||
| fi | ||||||||||||||||||
| export PATH="$(dirname "$MEMSOURCE_BIN"):$PATH" | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Authentication (credentials stay with the user) | ||||||||||||||||||
|
|
||||||||||||||||||
| **Do not** read `~/.memsourcerc`, Memsource passwords, or long-lived tokens into | ||||||||||||||||||
| the agent context. Phrase is a paid external service — treat credentials like | ||||||||||||||||||
| any other secret. | ||||||||||||||||||
|
|
||||||||||||||||||
| Preferred flow: | ||||||||||||||||||
|
|
||||||||||||||||||
| 1. Ask the user to authenticate in **their own terminal** and confirm | ||||||||||||||||||
| `memsource auth whoami` works (and that `MEMSOURCE_TOKEN` is exported in the | ||||||||||||||||||
| shell they will use for `npm run memsource-*`). | ||||||||||||||||||
| 2. The agent may run extract/export/validation without credentials. | ||||||||||||||||||
| 3. For upload/download/status, either: | ||||||||||||||||||
| - the user runs the `memsource-*` commands themselves after the agent prepares | ||||||||||||||||||
| artifacts, or | ||||||||||||||||||
| - the user has already exported a **short-lived** `MEMSOURCE_TOKEN` in the | ||||||||||||||||||
| shared shell (never paste the password into chat). | ||||||||||||||||||
|
|
||||||||||||||||||
| If a shared shell already has `MEMSOURCE_TOKEN`, verify with: | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| memsource auth whoami | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| If auth fails, stop and ask the user to refresh the token outside the agent. | ||||||||||||||||||
| Also ensure `jq` is installed (`brew install jq`) — upload scripts need it. | ||||||||||||||||||
|
|
||||||||||||||||||
| --- | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Critical nuances | ||||||||||||||||||
|
|
||||||||||||||||||
| ### 1. zh-cn vs zh filesystem mismatch | ||||||||||||||||||
|
|
||||||||||||||||||
| `i18n-scripts/languages.sh` uses `zh-cn`, but locales live under `locales/zh/`. | ||||||||||||||||||
| Without a symlink, `i18n-to-po` cannot merge existing Chinese translations and | ||||||||||||||||||
| uploads empty msgstr for Chinese. | ||||||||||||||||||
|
|
||||||||||||||||||
| **Before any `export-pos` during upload**, create the symlink and register | ||||||||||||||||||
| unconditional cleanup (also on failure / cancel): | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| ln -sfn zh locales/zh-cn | ||||||||||||||||||
| trap 'rm -f locales/zh-cn; rm -rf po-files locales/tmp' EXIT | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
Comment on lines
+83
to
+89
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
tmp=$(mktemp -d)
mkdir -p "$tmp/locales"
(
ln -s zh "$tmp/locales/zh-cn"
trap 'rm -f "$tmp/locales/zh-cn"' EXIT
)
test ! -e "$tmp/locales/zh-cn"
echo "A separate shell removes the symlink before the next workflow step."Repository: openshift/nmstate-console-plugin Length of output: 238 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf 'Tracked skill file exists:\n'
ls -l .cursor/skills/i18n-memsource/SKILL.md
printf '\nRelevant upload section (lines 60-115):\n'
sed -n '60,115p' .cursor/skills/i18n-memsource/SKILL.md | cat -n -v
printf '\nCleanup/export-pos references around lines 180-215:\n'
sed -n '180,215p' .cursor/skills/i18n-memsource/SKILL.md | cat -n -v
printf '\nAll export-pos / cleanup mentions in file:\n'
rg -n 'export-pos|rm -f|trap|locales/zh-cn|cleanup|po-files|locales/tmp' .cursor/skills/i18n-memsource/SKILL.mdRepository: openshift/nmstate-console-plugin Length of output: 4996 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf 'Upload workflow section (lines 170-330):\n'
sed -n '170,330p' .cursor/skills/i18n-memsource/SKILL.md | nl -ba
printf '\nCommand block formatting around upload steps:\n'
rg -n '^<{3}bash|^```(bash)?|### Step 5|### Step 6|### Step 7|### Step 8|export-pos|cleanup|rm -f|rm -rf' .cursor/skills/i18n-memsource/SKILL.mdRepository: openshift/nmstate-console-plugin Length of output: 251 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf 'Upload workflow section (lines 170-330):\n'
sed -n '170,330p' .cursor/skills/i18n-memsource/SKILL.md | awk '{printf "%6d\t%s\n", NR+169, $0}'
printf '\nCommand block references in upload workflow:\n'
rg -n '^<\|bash|<\|bash|^```(bash)?|### Step 5|### Step 6|### Step 7|### Step 8|export-pos|cleanup|rm -f|rm -rf' .cursor/skills/i18n-memsource/SKILL.mdRepository: openshift/nmstate-console-plugin Length of output: 7319 🏁 Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
p = Path('.cursor/skills/i18n-memsource/SKILL.md')
s = p.read_text()
steps = [i for i, line in enumerate(s.splitlines(), 1) if "### Step " in line]
print("Step headings:", steps)
for start in steps:
line = s.splitlines()[start-1]
raw = line.replace('###', '').replace(':', '').strip()
print(f"{start}: {raw}")
print("\nFenced bash block starts:")
for i, line in enumerate(s.splitlines(), 1):
if line.startswith("```bash"):
print(i)
print("\nTrap command starts:")
for i, line in enumerate(s.splitlines(), 1):
if line.startswith("trap "):
print(f"{i}: {line}")
PYRepository: openshift/nmstate-console-plugin Length of output: 1000 Ensure the upload cleanup trap survives until Step 8. The 🧰 Tools🪛 SkillSpector (2.5.1)[warning] 149: [RA2] Session Persistence: Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction. Remediation: Remove any persistence mechanisms (cron jobs, startup scripts, state files). Skills should not maintain state across sessions without explicit user consent. (Rogue Agent (RA2)) 🤖 Prompt for AI Agents |
||||||||||||||||||
|
|
||||||||||||||||||
| Download already maps `zh-cn` → `zh`. | ||||||||||||||||||
|
|
||||||||||||||||||
| ### 2. PO generation preserves existing translations | ||||||||||||||||||
|
|
||||||||||||||||||
| `i18n-to-po.js`: | ||||||||||||||||||
|
|
||||||||||||||||||
| 1. Start from English keys in `locales/en/` | ||||||||||||||||||
| 2. Clear values (empty placeholders) | ||||||||||||||||||
| 3. Merge existing values from `locales/<lang>/` | ||||||||||||||||||
| 4. Convert to PO via `i18next-conv` | ||||||||||||||||||
|
|
||||||||||||||||||
| Never skip `export-pos` or hand-build English-only POs. | ||||||||||||||||||
|
|
||||||||||||||||||
| ### 3. English placeholders must be empty in uploaded POs | ||||||||||||||||||
|
|
||||||||||||||||||
| `i18next-parser` + `useKeysAsDefaultValue: true` can leave English text in | ||||||||||||||||||
| secondary locale JSON. Old `i18n-to-po` copies that into `msgstr`, which Phrase | ||||||||||||||||||
| may treat as already translated. | ||||||||||||||||||
|
|
||||||||||||||||||
| **Desired PO state before upload:** | ||||||||||||||||||
|
|
||||||||||||||||||
| | Locale JSON value | msgstr in PO | | ||||||||||||||||||
| |-------------------|--------------| | ||||||||||||||||||
| | Real non-English translation | Keep it (carry forward) | | ||||||||||||||||||
| | Empty `""` | Empty (needs translation) | | ||||||||||||||||||
| | English placeholder (== English source) | **Empty** (needs translation) | | ||||||||||||||||||
|
|
||||||||||||||||||
| `export-pos.sh` runs `i18n-scripts/clear-english-msgstr.js` after generating POs | ||||||||||||||||||
| to clear `msgstr` when it equals `msgid`. Because `memsource-upload.sh` re-runs | ||||||||||||||||||
| `export-pos`, that clear also applies to the files that get uploaded. | ||||||||||||||||||
|
|
||||||||||||||||||
| This clear step is **redundant** if the repo migrates to | ||||||||||||||||||
| [`ocp-plugin-i18n-scripts`](https://github.com/avivtur/ocp-plugin-i18n-scripts), | ||||||||||||||||||
| which filters English placeholders during PO generation. | ||||||||||||||||||
|
|
||||||||||||||||||
| ### 4. Download clean-git check is wrong | ||||||||||||||||||
|
|
||||||||||||||||||
| `memsource-download.sh` checks `public/locales` / `packages/**/locales`, but this | ||||||||||||||||||
| repo uses root `locales/`. Before download, verify: | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| git status --short --untracked-files -- locales/ | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| --- | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Action 1: Upload Translations | ||||||||||||||||||
|
|
||||||||||||||||||
| Trigger: "upload translations", "memsource upload", "i18n upload", "send for translation" | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Checklist | ||||||||||||||||||
|
|
||||||||||||||||||
| ```text | ||||||||||||||||||
| Upload Progress: | ||||||||||||||||||
| - [ ] Step 1: Load state | ||||||||||||||||||
| - [ ] Step 2: Get VERSION from user, auto-increment SPRINT | ||||||||||||||||||
| - [ ] Step 3: Confirm user-provided Memsource auth (no credential access) | ||||||||||||||||||
| - [ ] Step 4: Extract translation keys | ||||||||||||||||||
| - [ ] Step 5: Create zh-cn symlink, generate PO files, clear English msgstr | ||||||||||||||||||
| - [ ] Step 6: Validate PO files | ||||||||||||||||||
| - [ ] Step 7: Show summary and get approval | ||||||||||||||||||
| - [ ] Step 8: Upload to Memsource (user shell / short-lived token only) | ||||||||||||||||||
| - [ ] Step 9: Cleanup and update state | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Step 1: Load state | ||||||||||||||||||
|
|
||||||||||||||||||
| Read `.cursor/skills/i18n-memsource/state.json`. | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Step 2: Get VERSION and SPRINT | ||||||||||||||||||
|
|
||||||||||||||||||
| - Always ask the user for VERSION. Do not assume. | ||||||||||||||||||
| - Auto-increment SPRINT from state (previous + 1). | ||||||||||||||||||
| - Show: "Uploading VERSION X, Sprint Y (branch: Z)" | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| git branch --show-current | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Step 3: Confirm authentication | ||||||||||||||||||
|
|
||||||||||||||||||
| Do **not** source `~/.memsourcerc` or request the password in chat. Ask the user | ||||||||||||||||||
| to authenticate in their terminal, then verify `memsource auth whoami` in the | ||||||||||||||||||
| shell that will run upload (or have the user run Step 8 themselves). | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Step 4: Extract translation keys | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| npm run i18n | ||||||||||||||||||
| # → i18next … -c i18next-parser.config.js && node ./i18n-scripts/set-english-defaults.js | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| Then show: | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| git status --short -- locales/ | ||||||||||||||||||
| git diff --stat -- locales/ | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| Require approval if the locale diff looks wrong. | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Step 5: zh-cn symlink + export POs + clear English msgstr | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| ln -sfn zh locales/zh-cn | ||||||||||||||||||
| trap 'rm -f locales/zh-cn; rm -rf po-files locales/tmp' EXIT | ||||||||||||||||||
| rm -rf po-files | ||||||||||||||||||
| npm run export-pos | ||||||||||||||||||
| # export-pos ends with: node ./i18n-scripts/clear-english-msgstr.js | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| Keep the symlink until after Step 8 (`memsource-upload` re-runs `export-pos`, | ||||||||||||||||||
| which also re-runs the clear step). The `trap` ensures cleanup even if a later | ||||||||||||||||||
| step fails. | ||||||||||||||||||
|
|
||||||||||||||||||
| If validating a hand-run export that skipped the script hook: | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| node ./i18n-scripts/clear-english-msgstr.js | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Step 6: Validate PO files | ||||||||||||||||||
|
|
||||||||||||||||||
| After the clear step, English placeholders should be empty. Report: | ||||||||||||||||||
|
|
||||||||||||||||||
| - **translated** = non-empty msgstr and msgstr ≠ msgid (real carry-forward) | ||||||||||||||||||
| - **needs translation** = empty msgstr (includes former English placeholders) | ||||||||||||||||||
| - **english_leaks remaining** = msgstr == msgid (should be 0 after clear) | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| for lang in ja zh-cn ko fr es; do | ||||||||||||||||||
| echo "=== $lang ===" | ||||||||||||||||||
| python3 -c " | ||||||||||||||||||
| import re, glob, sys | ||||||||||||||||||
| files = glob.glob(f'po-files/{sys.argv[1]}/*.po') | ||||||||||||||||||
| content = ''.join(open(f).read() for f in files) | ||||||||||||||||||
| entries = re.findall(r'msgid \"((?:\\\\.|[^\"])*)\"\s*msgstr \"((?:\\\\.|[^\"])*)\"', content) | ||||||||||||||||||
| entries = [(a,b) for a,b in entries if a] | ||||||||||||||||||
| translated = sum(1 for a,b in entries if b and b != a) | ||||||||||||||||||
| needs = sum(1 for a,b in entries if not b) | ||||||||||||||||||
| leaks = sum(1 for a,b in entries if b and b == a) | ||||||||||||||||||
| print(f' total={len(entries)} translated={translated} needs_translation={needs} english_leaks_remaining={leaks}') | ||||||||||||||||||
| " "$lang" | ||||||||||||||||||
| done | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| Warn if `english_leaks_remaining > 0`. | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Step 7: Show summary and get approval | ||||||||||||||||||
|
|
||||||||||||||||||
| Present plugin, version, sprint, branch, validation results, and project title. | ||||||||||||||||||
| Ask for explicit approval before upload. | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Step 8: Upload to Memsource | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| npm run memsource-upload -- -v "$VERSION" -s "$SPRINT" | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| Capture `PROJECT_ID` (`.uid`) from `memsource project create` output. | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Step 9: Cleanup and update state | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| rm -f locales/zh-cn | ||||||||||||||||||
| rm -rf po-files locales/tmp | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| Update `state.json` with `version`, `sprint`, `lastProjectId`, `memsourceProjectUrl`, and history. | ||||||||||||||||||
|
|
||||||||||||||||||
| Draft notification: | ||||||||||||||||||
|
|
||||||||||||||||||
| ```text | ||||||||||||||||||
| Subject: [OCP VERSION] Translation Upload - nmstate-console-plugin Sprint SPRINT | ||||||||||||||||||
|
|
||||||||||||||||||
| Hi Localization Team, | ||||||||||||||||||
|
|
||||||||||||||||||
| New translation strings have been uploaded for nmstate-console-plugin | ||||||||||||||||||
| (OCP VERSION, Sprint SPRINT). | ||||||||||||||||||
|
|
||||||||||||||||||
| Memsource project: https://cloud.memsource.com/web/project2/show/PROJECT_ID | ||||||||||||||||||
|
|
||||||||||||||||||
| Languages: ja, zh-cn, ko, fr, es | ||||||||||||||||||
| Total keys: N | ||||||||||||||||||
|
|
||||||||||||||||||
| Please review and translate at your convenience. Let us know when translations | ||||||||||||||||||
| are ready for download. | ||||||||||||||||||
|
|
||||||||||||||||||
| Thanks | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| --- | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Action 2: Download Translations | ||||||||||||||||||
|
|
||||||||||||||||||
| Trigger: "download translations", "memsource download", "i18n download", "get translations" | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Checklist | ||||||||||||||||||
|
|
||||||||||||||||||
| ```text | ||||||||||||||||||
| Download Progress: | ||||||||||||||||||
| - [ ] Step 1: Load state / confirm PROJECT_ID | ||||||||||||||||||
| - [ ] Step 2: Confirm user-provided Memsource auth | ||||||||||||||||||
| - [ ] Step 3: Check translation status | ||||||||||||||||||
| - [ ] Step 4: Ensure locales/ is clean | ||||||||||||||||||
| - [ ] Step 5: Download translations | ||||||||||||||||||
| - [ ] Step 6: Show diff summary | ||||||||||||||||||
| - [ ] Step 7: Create PR (optional) | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Step 1: Confirm PROJECT_ID | ||||||||||||||||||
|
|
||||||||||||||||||
| Show `lastProjectId` from state; ask to confirm or override. | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Step 2: Confirm authentication | ||||||||||||||||||
|
|
||||||||||||||||||
| Same as upload Step 3 — user-owned credentials only; no `~/.memsourcerc` in agent context. | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Step 3: Status | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| for lang in ja zh-cn ko fr es; do | ||||||||||||||||||
| memsource job list \ | ||||||||||||||||||
| --project-id "$PROJECT_ID" \ | ||||||||||||||||||
| --target-lang "$lang" \ | ||||||||||||||||||
| -f json \ | ||||||||||||||||||
| -c uid,status,targetLang | ||||||||||||||||||
| done | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| Warn if not all completed; ask before proceeding. | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Step 4: Clean locales | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| git status --short --untracked-files -- locales/ | ||||||||||||||||||
| # Must be clean — commit or stash first | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Step 5: Download | ||||||||||||||||||
|
|
||||||||||||||||||
| Create/switch to the PR branch **before** download (the script auto-commits): | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| git checkout -b "chore/i18n-update-sprint-${SPRINT}" | ||||||||||||||||||
| npm run memsource-download -- -p "$PROJECT_ID" | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
Comment on lines
+332
to
+337
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Define The download workflow confirms Load Proposed workflow fix+SPRINT=$(jq -er '.sprint' .cursor/skills/i18n-memsource/state.json)
+BRANCH="chore/i18n-update-sprint-${SPRINT}"
+
+if git show-ref --verify --quiet "refs/heads/${BRANCH}"; then
+ git switch "$BRANCH"
+else
+ git switch -c "$BRANCH"
+fi
+
-git checkout -b "chore/i18n-update-sprint-${SPRINT}"
npm run memsource-download -- -p "$PROJECT_ID"📝 Committable suggestion
Suggested change
🧰 Tools🪛 SkillSpector (2.5.1)[warning] 149: [RA2] Session Persistence: Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction. Remediation: Remove any persistence mechanisms (cron jobs, startup scripts, state files). Skills should not maintain state across sessions without explicit user consent. (Rogue Agent (RA2)) 🤖 Prompt for AI Agents |
||||||||||||||||||
|
|
||||||||||||||||||
| This downloads POs, converts with `po-to-i18n` (`zh-cn` → `zh`), and auto-commits. | ||||||||||||||||||
|
|
||||||||||||||||||
| ### Step 6–7: Diff + optional PR | ||||||||||||||||||
|
|
||||||||||||||||||
| ```bash | ||||||||||||||||||
| git diff HEAD~1 --stat -- locales/ | ||||||||||||||||||
|
|
||||||||||||||||||
| git push -u origin HEAD | ||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||||||||||||||
| gh pr create --title "chore(i18n): update translations for Sprint ${SPRINT}" --body "$(cat <<EOF | ||||||||||||||||||
| ## Summary | ||||||||||||||||||
| - Downloaded translations from Memsource project ${PROJECT_ID} | ||||||||||||||||||
| - Languages: ja, zh-cn, ko, fr, es | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Memsource Project | ||||||||||||||||||
| https://cloud.memsource.com/web/project2/show/${PROJECT_ID} | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Test plan | ||||||||||||||||||
| - [ ] Verify locale files are valid JSON | ||||||||||||||||||
| - [ ] Spot-check translations in the UI | ||||||||||||||||||
|
|
||||||||||||||||||
| Resolves: None | ||||||||||||||||||
| EOF | ||||||||||||||||||
| )" | ||||||||||||||||||
| ``` | ||||||||||||||||||
|
|
||||||||||||||||||
| --- | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Action 3: Status only | ||||||||||||||||||
|
|
||||||||||||||||||
| 1. Load `lastProjectId` (confirm/override) | ||||||||||||||||||
| 2. Authenticate | ||||||||||||||||||
| 3. Run job list for each language | ||||||||||||||||||
| 4. If all completed, suggest download | ||||||||||||||||||
|
|
||||||||||||||||||
| --- | ||||||||||||||||||
|
|
||||||||||||||||||
| ## Important reminders | ||||||||||||||||||
|
|
||||||||||||||||||
| - Always symlink `locales/zh-cn` → `zh` before upload `export-pos`; remove after upload | ||||||||||||||||||
| - Never skip `export-pos` (it preserves real translations and clears English placeholders) | ||||||||||||||||||
| - After export, `needs_translation` should cover empty msgstr; `english_leaks_remaining` should be 0 | ||||||||||||||||||
| - Clean root `locales/` before download | ||||||||||||||||||
| - Update `state.json` after successful upload | ||||||||||||||||||
| - Glob PO files (`*.po`); do not hard-code PO basenames (this repo uses `public__` prefix) | ||||||||||||||||||
| - If this repo migrates to `ocp-plugin-i18n-scripts`, remove `clear-english-msgstr.js` from `export-pos.sh` (redundant) | ||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Use one PO filename contract.
Line [32] documents
plugin__nmstate-console-plugin.po. Line [382] says that PO basenames must not be hard-coded because this repository uses apublic__prefix. These instructions conflict.Use
po-files/<lang>/*.poin the configuration, or document the verified generated basename in both locations.Proposed documentation fix
Also applies to: 382-382
🧰 Tools
🪛 SkillSpector (2.5.1)
[warning] 149: [RA2] Session Persistence: Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
Remediation: Remove any persistence mechanisms (cron jobs, startup scripts, state files). Skills should not maintain state across sessions without explicit user consent.
(Rogue Agent (RA2))
🤖 Prompt for AI Agents