This file gives specific instructions for AI agents that perform housekeeping tasks for Git l10n. Use of AI is optional; many successful l10n teams work well without it.
The section “Housekeeping tasks for localization workflows” documents the most commonly used housekeeping tasks:
Essential background for the workflows below; understand these concepts before performing any housekeeping tasks in this document.
XX is a placeholder for the language code: either ll (ISO 639) or ll_CC (e.g. de, zh_CN). It appears in the PO file header metadata (e.g. "Language: zh_CN\n") and is typically used to name the PO file: po/XX.po.
The header entry is the first entry in every po/XX.po. It has an empty msgid; translation metadata (project, language, plural rules, encoding, etc.) is stored in msgstr, as in this example:
msgid "" msgstr "" "Project-Id-Version: Git\n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
CRITICAL: Do not edit the header's msgstr while translating. It holds metadata only and must be left unchanged.
PO files may have a glossary in comments before the header entry (first msgid ""), giving terminology guidelines (e.g.):
# Git glossary for Chinese translators # # English | Chinese # ---------------------------------+-------------------------------------- # 3-way merge | 三路合并 # ...
IMPORTANT: Read and use the glossary when translating or reviewing. It is in # comments only. Leave that comment block unchanged.
PO entries are msgid / msgstr pairs. Plural messages add msgid_plural and msgstr[n]. The msgid is the immutable source; msgstr is the target translation. Each side may be a single quoted string or a multi-line block. In the multi-line form the header line is often msgid "" / msgstr "", with the real text split across following quoted lines (concatenated by Gettext).
Single-line entries:
msgid "commit message" msgstr "提交说明"
Multi-line entries:
msgid "" "Line 1\n" "Line 2" msgstr "" "行 1\n" "行 2"
CRITICAL: Do not use grep '^msgstr ""' to find untranslated entries; multi-line msgstr blocks use the same opening line, so grep gives false positives. Use msgattrib (next section).
Use msgattrib to list untranslated, fuzzy, and obsolete entries. Task 3 (translating po/XX.po) uses these commands.
msgattrib --untranslated --no-obsolete po/XX.pomsgattrib --only-fuzzy --no-obsolete po/XX.po#~): msgattrib --obsolete --no-wrap po/XX.poFuzzy entries need re-translation because the source text changed. The format differs by file type:
#, fuzzy tag in the entry comments marks the entry as fuzzy."fuzzy": true.Translation principles: Re-translate the msgstr (and, for plural entries, msgstr[n]) into the target language. Do not modify msgid or msgid_plural. After translation, clear the fuzzy mark: in PO, remove the #, fuzzy tag from comments; in JSON, omit or set fuzzy to false.
Preserve escape sequences (\n, \", \\, \t), placeholders (%s, %d, etc.), and quotes exactly as in msgid. Only reorder placeholders with positional syntax when needed (see Placeholder Reordering below).
When reordering placeholders relative to msgid, use positional syntax (%n$) where n is the 1-based argument index, so each argument still binds to the right value. Preserve width and precision modifiers, and place %n$ before them (see examples below).
Example 1 (placeholder reordering with precision):
msgid "missing environment variable '%s' for configuration '%.*s'" msgstr "配置 '%3$.*2$s' 缺少环境变量 '%1$s'"
%s → argument 1 → %1$s. %.*s needs precision (arg 2) and string (arg 3) → %3$.*2$s.
Example 2 (multi-line, four %s reordered):
msgid "" "Path updated: %s renamed to %s in %s, inside a directory that was renamed in " "%s; moving it to %s." msgstr "" "路径已更新:%1$s 在 %3$s 中被重命名为 %2$s,而其所在目录又在 %4$s 中被重命" "名,因此将其移动到 %5$s。"
Original order 1,2,3,4,5; in translation 1,3,2,4,5. Each line must be a complete quoted string.
Example 3 (no placeholder reordering):
msgid "MIDX %s must be an ancestor of %s" msgstr "MIDX %s 必须是 %s 的祖先"
Argument order is still 1,2 in translation, so %n$ is not needed. If no placeholder reordering occurs, you must not introduce %n$ syntax; keep the original non-positional placeholders (%s, %d, etc.).
Check the PO file using the command below:
msgfmt --check -o /dev/null po/XX.po
Common validation errors include:
On failure, msgfmt prints the line number; fix the PO at that line.
git-po-helper supports Git l10n with quality checking (git-l10n PR conventions) and AI-assisted translation (subcommands for automated workflows). Housekeeping tasks in this document use it when available; otherwise rely on gettext tools.
When a PO file is too large for translation or review, use git-po-helper msg-select to split it by entry index.
--no-header to omit).--range "1-50" (entries 1 through 50), --range "-50" (first 50 entries), --range "51-" (from entry 51 to end). Shortcuts: --head N (first N), --tail N (last N), --since N (from N to end).--json for GETTEXT JSON. See the “GETTEXT JSON format” section (under git-po-helper) for details.--translated, --untranslated, --fuzzy to filter by state (OR relationship). Use --no-obsolete to exclude obsolete entries; --with-obsolete to include (default). Use --only-same or --only-obsolete for a single state. Range applies to the filtered list.# First 50 entries (header + entries 1–50) git-po-helper msg-select --range "-50" po/in.po -o po/out.po # Entries 51–100 git-po-helper msg-select --range "51-100" po/in.po -o po/out.po # Entries 101 to end git-po-helper msg-select --range "101-" po/in.po -o po/out.po # Entries 1–50 without header (content only) git-po-helper msg-select --range "1-50" --no-header po/in.po -o po/frag.po # Output as JSON; select untranslated and fuzzy entries, exclude obsolete git-po-helper msg-select --json --untranslated --fuzzy --no-obsolete po/in.po >po/filtered.json
git-po-helper compare shows PO changes with full entry context (unlike git diff). Redirect output to a file: it is empty when there are no new or changed entries; otherwise it contains a valid PO header.
# Get full context of local changes (HEAD vs working tree) git-po-helper compare po/XX.po -o po/out.po # Get full context of changes in a specific commit (parent vs commit) git-po-helper compare --commit <commit> po/XX.po -o po/out.po # Get full context of changes since a commit (commit vs working tree) git-po-helper compare --since <commit> po/XX.po -o po/out.po # Get full context between two commits git-po-helper compare -r <commit1>..<commit2> po/XX.po -o po/out.po # Get full context of two worktree files git-po-helper compare po/old.po po/new.po -o po/out.po # Check msgid consistency (detect tampering); no output means target matches source git-po-helper compare --msgid po/old.po po/new.po >po/out.po
Options summary
| Option | Meaning |
|---|---|
| (none) | Compare HEAD with working tree (local changes) |
--commit <commit> | Compare parent of commit with the commit |
--since <commit> | Compare commit with working tree |
-r x..y | Compare revision x with revision y |
-r x.. | Compare revision x with working tree |
-r x | Compare parent of x with x |
git-po-helper msg-cat merges PO, POT, or gettext JSON inputs into one stream. Duplicate msgid values keep the first occurrence in file order. Write with -o <file> or stdout (-o - or omit); --json selects JSON output, else PO.
# Convert JSON to PO (e.g. after translation) git-po-helper msg-cat --unset-fuzzy -o po/out.po po/in.json # Merge multiple PO files git-po-helper msg-cat -o po/out.po po/in-1.po po/in-2.json
The GETTEXT JSON format is an internal format defined by git-po-helper for convenient batch processing of translation and related tasks by AI models. git-po-helper msg-select, git-po-helper msg-cat, and git-po-helper compare read and write this format.
Top-level structure:
{ "header_comment": "string", "header_meta": "string", "entries": [ /* array of entry objects */ ] }
| Field | Description |
|---|---|
header_comment | Lines above the first msgid "" (comments, glossary), directly concatenated. |
header_meta | Encoded msgstr of the header entry (Project-Id-Version, Plural-Forms, etc.). |
entries | List of PO entries. Order matches source. |
Entry object (each element of entries):
| Field | Type | Description |
|---|---|---|
msgid | string | Singular message ID. PO escapes encoded (e.g. \n → \\n). |
msgstr | []string | Translation forms as a JSON array only. Details below. |
msgid_plural | string | Plural form of msgid. Omit for non-plural. |
comments | []string | Comment lines (#, #., #:, #,, etc.). |
fuzzy | bool | True if entry has fuzzy flag. |
obsolete | bool | True for #~ obsolete entries. Omit if false. |
msgstr array (required shape):
msgstr / msgstr[0]); multiple elements = plural forms in order (msgstr[0], msgstr[1], …).Example (single-line entry):
{ "header_comment": "# Glossary:\\n# term1\\tTranslation 1\\n#\\n", "header_meta": "Project-Id-Version: git\\nContent-Type: text/plain; charset=UTF-8\\n", "entries": [ { "msgid": "Hello", "msgstr": ["你好"], "comments": ["#. Comment for translator\\n", "#: src/file.c:10\\n"], "fuzzy": false } ] }
Example (plural entry):
{ "msgid": "One file", "msgid_plural": "%d files", "msgstr": ["一个文件", "%d 个文件"], "comments": ["#, c-format\\n"] }
Example (fuzzy entry before translation):
{ "msgid": "Old message", "msgstr": ["旧翻译。"], "comments": ["#, fuzzy\\n"], "fuzzy": true }
Translation notes for GETTEXT JSON files:
header_comment, header_meta, msgid, msgid_plural unchanged."fuzzy": true. After translating, remove the fuzzy field or set it to false in the output JSON. The merge step uses --unset-fuzzy, which can also remove the fuzzy field.%s, %d, etc. exactly; use %n$ when reordering (see “Placeholder Reordering” above).%s, {name}, $1) exactly; use positional parameters when reordering (see “Placeholder Reordering” above).\n, \", \\, \t), placeholders exactly as in msgid. See “Preserving Special Characters” above.For common housekeeping tasks, follow the steps in the matching subsection below.
When asked to generate or update po/git.pot (or the like):
Directly execute the command make po/git.pot without checking if the file exists beforehand.
Do not verify the generated file after execution. Simply run the command and consider the task complete.
When asked to update po/XX.po (or the like):
Directly execute the command make po-update PO_FILE=po/XX.po without reading or checking the file content beforehand.
Do not verify, translate, or review the updated file after execution. Simply run the command and consider the task complete.
To translate po/XX.po, use the steps below. The script uses gettext or git-po-helper depending on what is installed; JSON export (when available) supports batch translation rather than per-entry work.
Workflow loop: Steps 1→2→3→4→5→6→7 form a loop. After step 6 succeeds, always go to step 7, which returns to step 1. The only exit to step 8 is when step 2 finds po/l10n-pending.po empty. Do not skip step 7 or jump to step 8 after step 6.
Extract entries to translate: Directly execute the script below—it is authoritative; do not reimplement. It generates po/l10n-pending.po with messages that need translation.
l10n_extract_pending () { test $# -ge 1 || { echo "Usage: l10n_extract_pending <po-file>" >&2; return 1; } PO_FILE="$1" PENDING="po/l10n-pending.po" PENDING_FUZZY="${PENDING}.fuzzy" PENDING_REFER="${PENDING}.fuzzy.reference" PENDING_UNTRANS="${PENDING}.untranslated" rm -f "$PENDING" if command -v git-po-helper >/dev/null 2>&1 then git-po-helper msg-select --untranslated --fuzzy --no-obsolete -o "$PENDING" "$PO_FILE" else msgattrib --untranslated --no-obsolete "$PO_FILE" >"${PENDING_UNTRANS}" msgattrib --only-fuzzy --no-obsolete --clear-fuzzy --empty "$PO_FILE" >"${PENDING_FUZZY}" msgattrib --only-fuzzy --no-obsolete "$PO_FILE" >"${PENDING_REFER}" msgcat --use-first "${PENDING_UNTRANS}" "${PENDING_FUZZY}" >"$PENDING" rm -f "${PENDING_UNTRANS}" "${PENDING_FUZZY}" fi if test -s "$PENDING" then msgfmt --stat -o /dev/null "$PENDING" || true echo "Pending file is not empty; there are still entries to translate." else echo "No entries need translation." return 1 fi } # Run the extraction. Example: l10n_extract_pending po/zh_CN.po l10n_extract_pending po/XX.po
Check generated file: If po/l10n-pending.po is empty or does not exist, translation is complete; go to step 8. Otherwise proceed to step 3.
Prepare one batch for translation: Batching keeps each run small so the model can complete translation within limited context. BEFORE translating, directly execute the script below—it is authoritative; do not reimplement. Based on which file the script produces: if po/l10n-todo.json exists, go to step 4a; if po/l10n-todo.po exists, go to step 4b.
l10n_one_batch () { test $# -ge 1 || { echo "Usage: l10n_one_batch <po-file> [min_batch_size]" >&2; return 1; } PO_FILE="$1" min_batch_size=${2:-100} PENDING="po/l10n-pending.po" TODO_JSON="po/l10n-todo.json" TODO_PO="po/l10n-todo.po" DONE_JSON="po/l10n-done.json" DONE_PO="po/l10n-done.po" rm -f "$TODO_JSON" "$TODO_PO" "$DONE_JSON" "$DONE_PO" ENTRY_COUNT=$(grep -c '^msgid ' "$PENDING" 2>/dev/null || echo 0) ENTRY_COUNT=$((ENTRY_COUNT > 0 ? ENTRY_COUNT - 1 : 0)) if test "$ENTRY_COUNT" -gt $min_batch_size then if test "$ENTRY_COUNT" -gt $((min_batch_size * 8)) then NUM=$((min_batch_size * 2)) elif test "$ENTRY_COUNT" -gt $((min_batch_size * 4)) then NUM=$((min_batch_size + min_batch_size / 2)) else NUM=$min_batch_size fi BATCHING=1 else NUM=$ENTRY_COUNT BATCHING= fi if command -v git-po-helper >/dev/null 2>&1 then if test -n "$BATCHING" then git-po-helper msg-select --json --head "$NUM" -o "$TODO_JSON" "$PENDING" echo "Processing batch of $NUM entries (out of $ENTRY_COUNT remaining)" else git-po-helper msg-select --json -o "$TODO_JSON" "$PENDING" echo "Processing all $ENTRY_COUNT entries at once" fi else if test -n "$BATCHING" then awk -v num="$NUM" '/^msgid / && count++ > num {exit} 1' "$PENDING" | tac | awk '/^$/ {found=1} found' | tac >"$TODO_PO" echo "Processing batch of $NUM entries (out of $ENTRY_COUNT remaining)" else cp "$PENDING" "$TODO_PO" echo "Processing all $ENTRY_COUNT entries at once" fi fi } # Prepare one batch; shrink 2nd arg when batches exceed agent capacity. l10n_one_batch po/XX.po 100
4a. Translate JSON batch (po/l10n-todo.json → po/l10n-done.json):
po/l10n-todo.json (input, GETTEXT JSON) into po/l10n-done.json (output, GETTEXT JSON). See the “GETTEXT JSON format” section above for format details and translation rules.header_comment (see “Glossary Section” above) and use it for consistent terminology.\n, \", \\, \t), placeholders, and quotes correctly as in msgid. For JSON, correctly escape and unescape these sequences when reading and writing. Modify msgstr and msgstr[n] (for plural entries); clear the fuzzy flag (omit or set fuzzy to false). Do not modify msgid or msgid_plural.4b. Translate PO batch (po/l10n-todo.po → po/l10n-done.po):
po/l10n-todo.po (input, GETTEXT PO) into po/l10n-done.po (output, GETTEXT PO).\n, \", \\, \t), placeholders, and quotes as in msgid. Modify msgstr and msgstr[n] (for plural entries); remove the #, fuzzy tag from comments when done. Do not modify msgid or msgid_plural.Validate po/l10n-done.po:
Run the validation script below. If it fails, fix per the errors and notes, re-run until it succeeds.
l10n_validate_done () { DONE_PO="po/l10n-done.po" DONE_JSON="po/l10n-done.json" PENDING="po/l10n-pending.po" if test -f "$DONE_JSON" && { ! test -f "$DONE_PO" || test "$DONE_JSON" -nt "$DONE_PO"; } then git-po-helper msg-cat --unset-fuzzy -o "$DONE_PO" "$DONE_JSON" || { echo "ERROR [JSON to PO conversion]: Fix $DONE_JSON and re-run." >&2 return 1 } fi # Check 1: msgid should not be modified MSGID_OUT=$(git-po-helper compare -q --msgid --assert-no-changes \ "$PENDING" "$DONE_PO" 2>&1) MSGID_RC=$? if test $MSGID_RC -ne 0 || test -n "$MSGID_OUT" then echo "ERROR [msgid modified]: The following entries appeared after" >&2 echo "translation because msgid was altered. Fix in $DONE_PO." >&2 echo "$MSGID_OUT" >&2 return 1 fi # Check 2: PO format (see "Validating PO File Format" for error handling) MSGFMT_OUT=$(msgfmt --check -o /dev/null "$DONE_PO" 2>&1) MSGFMT_RC=$? if test $MSGFMT_RC -ne 0 then echo "ERROR [PO format]: Fix errors in $DONE_PO." >&2 echo "$MSGFMT_OUT" >&2 return 1 fi echo "Validation passed." } l10n_validate_done
If the script fails, fix directly in po/l10n-done.po. Re-run l10n_validate_done until it succeeds. Editing po/l10n-done.json is not recommended because it adds an extra JSON-to-PO conversion step. Use the error message to decide:
[msgid modified]: The listed entries have altered msgid; restore them to match po/l10n-pending.po.[PO format]: msgfmt reports line numbers; fix the errors in place. See “Validating PO File Format” for common issues.Merge translation results into po/XX.po: Run the script below. If it fails, fix the file the error names: [JSON to PO conversion] → po/l10n-done.json; [msgcat merge] → po/l10n-done.po. Re-run until it succeeds.
l10n_merge_batch () { test $# -ge 1 || { echo "Usage: l10n_merge_batch <po-file>" >&2; return 1; } PO_FILE="$1" DONE_PO="po/l10n-done.po" DONE_JSON="po/l10n-done.json" MERGED="po/l10n-done.merged" PENDING="po/l10n-pending.po" PENDING_REFER="${PENDING}.fuzzy.reference" TODO_JSON="po/l10n-todo.json" TODO_PO="po/l10n-todo.po" if test -f "$DONE_JSON" && { ! test -f "$DONE_PO" || test "$DONE_JSON" -nt "$DONE_PO"; } then git-po-helper msg-cat --unset-fuzzy -o "$DONE_PO" "$DONE_JSON" || { echo "ERROR [JSON to PO conversion]: Fix $DONE_JSON and re-run." >&2 return 1 } fi msgcat --use-first "$DONE_PO" "$PO_FILE" >"$MERGED" || { echo "ERROR [msgcat merge]: Fix errors in $DONE_PO and re-run." >&2 return 1 } mv "$MERGED" "$PO_FILE" rm -f "$TODO_JSON" "$TODO_PO" "$DONE_JSON" "$DONE_PO" "$PENDING_REFER" } # Run the merge. Example: l10n_merge_batch po/zh_CN.po l10n_merge_batch po/XX.po
Loop: MUST return to step 1 (Extract entries) and repeat the cycle. Do not skip this step or go to step 8. Step 8 (below) runs only when step 2 finds no more entries and redirects there.
Only after loop exits: Run the command below to validate the PO file and display the report. The process ends here.
msgfmt --check --stat -o /dev/null po/XX.po
Review may target the full po/XX.po, a specific commit, or changes since a commit. When asked to review, follow the steps below.
Workflow: Follow steps in order. Do NOT use git show, git diff, git format-patch, or similar to get changes—they break PO context; use only git-po-helper compare for extraction. Without git-po-helper, refuse the task. Steps 3→4→5→6→7 loop: after step 6, always go to step 7 (back to step 3). The only ways to step 8 are when step 4 finds po/review-todo.json missing or empty (no batch left to review), or when step 1 finds po/review-result.json already present.
Check for existing review (resume support): Evaluate the following in order:
po/review-input.po does not exist, proceed to step 2 (Extract entries) for a fresh start.po/review-result.json exists, go to step 8 (only after loop exits).po/review-done.json exists, go to step 6 (Rename result).po/review-todo.json exists, go to step 5 (Review the current batch).Extract entries: Run git-po-helper compare with the desired range and redirect the output to po/review-input.po. See “Comparing PO files for translation and review” under git-po-helper for options.
Prepare one batch: Batching keeps each run small so the model can complete review within limited context. Directly execute the script below—it is authoritative; do not reimplement.
review_one_batch () { min_batch_size=${1:-100} INPUT_PO="po/review-input.po" PENDING="po/review-pending.po" TODO="po/review-todo.json" DONE="po/review-done.json" BATCH_FILE="po/review-batch.txt" if test ! -f "$INPUT_PO" then rm -f "$TODO" echo >&2 "cannot find $INPUT_PO, nothing for review" return 1 fi if test ! -f "$PENDING" || test "$INPUT_PO" -nt "$PENDING" then rm -f "$BATCH_FILE" "$TODO" "$DONE" rm -f po/review-result*.json cp "$INPUT_PO" "$PENDING" fi ENTRY_COUNT=$(grep -c '^msgid ' "$PENDING" 2>/dev/null || echo 0) ENTRY_COUNT=$((ENTRY_COUNT > 0 ? ENTRY_COUNT - 1 : 0)) if test "$ENTRY_COUNT" -eq 0 then rm -f "$TODO" echo >&2 "No entries left for review" return 1 fi if test "$ENTRY_COUNT" -gt $min_batch_size then if test "$ENTRY_COUNT" -gt $((min_batch_size * 8)) then NUM=$((min_batch_size * 2)) elif test "$ENTRY_COUNT" -gt $((min_batch_size * 4)) then NUM=$((min_batch_size + min_batch_size / 2)) else NUM=$min_batch_size fi else NUM=$ENTRY_COUNT fi BATCH=$(cat "$BATCH_FILE" 2>/dev/null || echo 0) BATCH=$((BATCH + 1)) echo "$BATCH" >"$BATCH_FILE" git-po-helper msg-select --json --head "$NUM" -o "$TODO" "$PENDING" git-po-helper msg-select --since "$((NUM + 1))" -o "${PENDING}.tmp" "$PENDING" mv "${PENDING}.tmp" "$PENDING" echo "Processing batch $BATCH ($NUM entries out of $ENTRY_COUNT)" } # The parameter controls batch size; reduce if the batch file is too large. review_one_batch 100
Check todo file: If po/review-todo.json does not exist or is empty, review is complete; go to step 8 (only after loop exits). Otherwise proceed to step 5.
Review the current batch: Review translations in po/review-todo.json and write findings to po/review-done.json as follows:
header_comment includes a glossary, follow it for consistency.header_comment, header_meta).msgstr array (translation forms) against msgid / msgid_plural using the “Quality checklist” above.{"issues": []} when there are no issues. Always write po/review-done.json—it marks the batch complete.Rename result: Rename po/review-done.json to po/review-result-<N>.json, where N is the value in po/review-batch.txt (the batch just completed). Run the script below:
review_rename_result () { TODO="po/review-todo.json" DONE="po/review-done.json" BATCH_FILE="po/review-batch.txt" if test -f "$DONE" then N=$(cat "$BATCH_FILE" 2>/dev/null) || { echo "ERROR: $BATCH_FILE not found." >&2; return 1; } mv "$DONE" "po/review-result-$N.json" echo "Renamed to po/review-result-$N.json" fi rm -f "$TODO" } review_rename_result
Loop: MUST return to step 3 (Prepare one batch) and repeat the cycle. Do not skip this step or go to step 8. Step 8 is reached only when step 4 finds po/review-todo.json missing or empty.
Only after loop exits: Directly execute the command below. It merges results, applies suggestions, and displays the report. The process ends here.
git-po-helper agent-run review --report po
Do not run cleanup or delete intermediate files. Keep them for inspection or resumption.
Review result JSON format:
The Review result JSON format defines the structure for translation review reports. For each entry with translation issues, create an issue object as follows:
msgid, optional msgid_plural, and optional msgstr array (original translation forms) into the issue object. Use the same shape as GETTEXT JSON: msgstr is always a JSON array when present (one element singular, multiple for plural).description.score according to the severity of issues found for this entry, from 0 to 3 (0 = critical; 1 = major; 2 = minor; 3 = perfect, no issues). Lower score means more severe issues.suggest_msgstr as a JSON array: one string for singular, multiple strings for plural forms in order. This is required for git-po-helper to apply suggestions.{"issues": []}.Example review result (with issues):
{ "issues": [ { "msgid": "commit", "msgstr": ["委托"], "score": 0, "description": "Terminology error: 'commit' should be translated as '提交'", "suggest_msgstr": ["提交"] }, { "msgid": "repository", "msgid_plural": "repositories", "msgstr": ["版本库", "版本库"], "score": 2, "description": "Consistency issue: suggest using '仓库' consistently", "suggest_msgstr": ["仓库", "仓库"] } ] }
Field descriptions for each issue object (element of the issues array):
msgid (and optional msgid_plural for plural entries): Original source text.msgstr (optional): JSON array of original translation forms (same meaning as in GETTEXT JSON entries).suggest_msgstr: JSON array of suggested translation forms; must be an array (e.g. ["提交"] for singular). Plural entries use multiple elements in order.score: 0–3 (0 = critical; 1 = major; 2 = minor; 3 = perfect, no issues).description: Brief summary of the issue.Git translation is human-driven; language team leaders and contributors are responsible for maintaining translation quality and consistency.
AI-generated output should always be treated as drafts that must be reviewed and approved by someone who understands both the technical context and the target language. The best results come from combining AI efficiency with human judgment, cultural insight, and community engagement.