android-localisation 1.1.3__tar.gz → 1.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. {android_localisation-1.1.3/android_localisation.egg-info → android_localisation-1.6.0}/PKG-INFO +279 -18
  2. {android_localisation-1.1.3 → android_localisation-1.6.0}/README.md +277 -16
  3. android_localisation-1.6.0/android_localisation/__init__.py +5 -0
  4. {android_localisation-1.1.3 → android_localisation-1.6.0}/android_localisation/cli.py +67 -8
  5. android_localisation-1.6.0/android_localisation/credentials.py +185 -0
  6. android_localisation-1.6.0/android_localisation/locales.py +72 -0
  7. android_localisation-1.6.0/android_localisation/store_listing.py +254 -0
  8. {android_localisation-1.1.3 → android_localisation-1.6.0}/android_localisation/translate.py +116 -46
  9. {android_localisation-1.1.3 → android_localisation-1.6.0/android_localisation.egg-info}/PKG-INFO +279 -18
  10. {android_localisation-1.1.3 → android_localisation-1.6.0}/android_localisation.egg-info/SOURCES.txt +3 -0
  11. {android_localisation-1.1.3 → android_localisation-1.6.0}/pyproject.toml +2 -2
  12. android_localisation-1.1.3/android_localisation/__init__.py +0 -5
  13. {android_localisation-1.1.3 → android_localisation-1.6.0}/LICENSE +0 -0
  14. {android_localisation-1.1.3 → android_localisation-1.6.0}/MANIFEST.in +0 -0
  15. {android_localisation-1.1.3 → android_localisation-1.6.0}/android_localisation/__main__.py +0 -0
  16. {android_localisation-1.1.3 → android_localisation-1.6.0}/android_localisation/fix.py +0 -0
  17. {android_localisation-1.1.3 → android_localisation-1.6.0}/android_localisation/java/VerifyStrings.java +0 -0
  18. {android_localisation-1.1.3 → android_localisation-1.6.0}/android_localisation/resources.py +0 -0
  19. {android_localisation-1.1.3 → android_localisation-1.6.0}/android_localisation/setup_path.py +0 -0
  20. {android_localisation-1.1.3 → android_localisation-1.6.0}/android_localisation/updates.py +0 -0
  21. {android_localisation-1.1.3 → android_localisation-1.6.0}/android_localisation/verify.py +0 -0
  22. {android_localisation-1.1.3 → android_localisation-1.6.0}/android_localisation.egg-info/dependency_links.txt +0 -0
  23. {android_localisation-1.1.3 → android_localisation-1.6.0}/android_localisation.egg-info/entry_points.txt +0 -0
  24. {android_localisation-1.1.3 → android_localisation-1.6.0}/android_localisation.egg-info/top_level.txt +0 -0
  25. {android_localisation-1.1.3 → android_localisation-1.6.0}/setup.cfg +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: android-localisation
3
- Version: 1.1.3
4
- Summary: Zero-dependency Android strings.xml translation and verification using LLMs (Gemini, OpenAI, Anthropic, Ollama).
3
+ Version: 1.6.0
4
+ Summary: Zero-dependency Android strings.xml and Google Play store listing translation using LLMs (Gemini, OpenAI, Anthropic, Ollama).
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://github.com/BharathKmalviya/android-llm-localization
7
7
  Project-URL: Repository, https://github.com/BharathKmalviya/android-llm-localization
@@ -34,7 +34,7 @@ Dynamic: license-file
34
34
 
35
35
  **PyPI:** [`android-localisation`](https://pypi.org/project/android-localisation/) · **CLI:** `android-localise` · **Repo:** [android-llm-localization](https://github.com/BharathKmalviya/android-llm-localization)
36
36
 
37
- Translate your Android `strings.xml` into multiple languages using AI — Gemini, OpenAI, Anthropic, or a local model via Ollama. No paid translation service, no CSV exports, no copy-paste.
37
+ Translate your Android `strings.xml` and Google Play store listing into multiple languages using AI — Gemini, OpenAI, Anthropic, or a local model via Ollama.
38
38
 
39
39
  ---
40
40
 
@@ -121,12 +121,16 @@ That's the full workflow. Run these three commands after every time you update y
121
121
 
122
122
  When you run `android-localise translate --api-key YOUR_KEY`, here's exactly what it does:
123
123
 
124
- 1. Looks for `app/src/main/res/values/strings.xml` — this is your English source
125
- 2. If `--languages` is provided, selects those locales. Otherwise scans existing locale folders, skipping configuration-only folders such as `values-night`, `values-land`, `values-car`, and `values-sw600dp`
126
- 3. Sends your English XML to the LLM with app context and instructions to preserve resource structure, protected values, namespaces and format specifiers. With `--missing-only`, requests only resources absent from the target file; existing resources remain untouched, and complete locales make no API request
127
- 4. Parses the response and checks duplicate/unexpected/missing resources, attributes, inline markup, item structure, control escapes and format arguments. A valid result replaces the file atomically; new folders are created only when saving. `--dry-run` shows a diff without writing any files or creating folders
124
+ 1. Reads `app/src/main/res/values/strings.xml` by default, or the XML file supplied with `--source`. `--source-language` identifies its language (default `en-US`)
125
+ 2. Combines `--languages` and `--languages-file`, expands `all`, removes duplicates and applies `--exclude-languages`. Android qualifiers and conventional language tags are accepted. Without an explicit list, scans existing locale folders in the destination directory, skipping configuration-only folders such as `values-night`, `values-land`, `values-car`, and `values-sw600dp`. The destination defaults to `--res-dir`, or can be set with `--output-dir`
126
+ 3. Sends the source XML to the LLM with its language, app context and instructions to preserve resource structure, protected values, namespaces and format specifiers. With `--missing-only`, requests only resources absent from the target file; existing resources remain untouched, and complete locales make no API request
127
+ 4. Parses the response and checks duplicate/unexpected/missing resources, attributes, inline markup, item structure, control escapes and format arguments. A valid result replaces the file atomically; new folders are created only when saving. `--skip-existing` validates existing files and skips them without API calls. `--dry-run` shows a diff without writing any files or creating folders
128
128
  5. Waits 5 seconds between each language request to avoid hitting API rate limits
129
129
 
130
+ Keys resolve from `--api-key`, then provider environment variables / `API_KEY`,
131
+ then saved Windows credentials for built-in provider endpoints. The CLI never
132
+ prompts for a key during translation; use `credentials set` yourself beforehand.
133
+
130
134
  **Defaults used when you don't specify anything:**
131
135
 
132
136
  | What | Default |
@@ -145,7 +149,8 @@ Normal translation still replaces the whole locale file. Use `--missing-only` to
145
149
 
146
150
  ## Setup
147
151
 
148
- The only requirement is that `app/src/main/res/values/strings.xml` exists — your English source file.
152
+ Provide source XML at `app/src/main/res/values/strings.xml` by default, or supply
153
+ another file with `--source` and its language with `--source-language`.
149
154
 
150
155
  For target languages, you have two options:
151
156
 
@@ -155,6 +160,26 @@ android-localise translate --api-key YOUR_KEY --languages hi,es,fr,de
155
160
  ```
156
161
  This translates into Hindi, Spanish, French and German, creating each folder and `strings.xml` when its translation passes validation.
157
162
 
163
+ To translate into the same 86-locale catalog used for store listings:
164
+
165
+ ```bash
166
+ android-localise translate --api-key YOUR_KEY --languages all
167
+ ```
168
+
169
+ `all` is case-insensitive and can be combined with extra languages. The bundled catalog is shared
170
+ with `store-listing` and mapped to [Android resource qualifiers](https://developer.android.com/guide/topics/resources/providing-resources#AlternativeResources):
171
+ `hi-IN` becomes `values-hi-rIN`, `pt-BR` becomes `values-pt-rBR`, `es-419`
172
+ becomes `values-b+es+419`, and `fil` becomes `values-b+fil`. Regional variants,
173
+ including English ones, remain separate; `values/strings.xml` remains the source.
174
+ This is the bundled Play locale set, not every possible Android locale.
175
+
176
+ The same XML validation, atomic saves, delay, `--missing-only` and `--dry-run`
177
+ behavior applies to each locale. Normal translation refreshes existing files;
178
+ use `--languages all --missing-only` to keep reviewed resources. Generating or
179
+ previewing all locales can use 86 translation requests plus provider retries;
180
+ complete locales in missing-only mode skip API calls. No folders are created
181
+ during previews or before their translation passes validation.
182
+
158
183
  **Option B — pre-create folders yourself:**
159
184
  ```
160
185
  app/src/main/res/
@@ -164,7 +189,7 @@ app/src/main/res/
164
189
  ├── values-es/
165
190
  └── values-fr/
166
191
  ```
167
- Run `android-localise translate --api-key YOUR_KEY` and it picks up locale folders, creating `strings.xml` inside each one after successful translation. Locale examples include `values-hi`, `values-es-rES`, `values-b+zh+Hans`, and `values-en-night`; qualifier-only folders are skipped. `--languages` accepts the same forms without the optional `values-` prefix and rejects path separators or non-locale names.
192
+ Run `android-localise translate --api-key YOUR_KEY` and it picks up locale folders, creating `strings.xml` inside each one after successful translation. Locale examples include `values-hi`, `values-es-rES`, `values-b+zh+Hans`, and `values-en-night`; qualifier-only folders are skipped. `--languages` accepts the same forms without the optional `values-` prefix, plus conventional tags such as `es-ES` or `zh-Hant-TW`, and rejects path separators or non-locale names.
168
193
 
169
194
  **Get a free API key:** [Google Gemini AI Studio](https://aistudio.google.com/) → Get API Key. The free tier handles most apps without hitting limits.
170
195
 
@@ -177,6 +202,7 @@ typical workflow. Each command has detailed help with its options and examples:
177
202
 
178
203
  ```bash
179
204
  android-localise translate --help
205
+ android-localise store-listing --help
180
206
  android-localise fix --help
181
207
  android-localise verify --help
182
208
  android-localise models --help
@@ -204,10 +230,16 @@ android-localise translate \
204
230
 
205
231
  | Flag | What it does | Default |
206
232
  |---|---|---|
207
- | `--api-key` | Your API key | reads from env var |
233
+ | `--api-key` | Explicit key override; omit for environment or saved Windows credentials | environment, then saved Windows key |
208
234
  | `--provider` | Which AI to use: `gemini` `openai` `anthropic` `custom` | `gemini` |
209
235
  | `--model` | Specific model to use | see [Providers](#providers) |
210
- | `--languages` | Comma-separated language codes — creates folders and files automatically | — |
236
+ | `--languages` | Comma-separated Android/conventional codes and/or `all`, e.g. `all,zu` or `hi,es-ES,b+es+419` | scan existing destination locale folders |
237
+ | `--languages-file` | UTF-8 comma/newline language list; combines with `--languages` | none |
238
+ | `--exclude-languages` | Remove exact normalized locales after selection/discovery | none |
239
+ | `--source` | Read a custom XML source file | `RES_DIR/values/strings.xml` |
240
+ | `--source-language` | Language tag for source XML | `en-US` |
241
+ | `--output-dir` | Save translated XML into this Android res/ directory | `--res-dir` |
242
+ | `--skip-existing` | Validate and skip existing XML files without API calls | off; incompatible with `--missing-only` |
211
243
  | `--app-context` | One-line description of your app | — |
212
244
  | `--res-dir` | Path to your `res/` folder | `app/src/main/res` |
213
245
  | `--base-url` | API endpoint for local/custom providers | — |
@@ -229,6 +261,172 @@ Validation permits positional placeholder reordering such as `%s %d` becoming `%
229
261
 
230
262
  ---
231
263
 
264
+ ### `store-listing`
265
+
266
+ Translate an existing Google Play listing's **app name**, **short description**
267
+ and **full description**, using the same providers, keys, model defaults,
268
+ model-not-found fallbacks and timeout handling as `translate`.
269
+
270
+ Create a UTF-8 `listing.json` containing exactly these three nonempty strings:
271
+
272
+ ```json
273
+ {
274
+ "app_name": "Pocket Notes",
275
+ "short_description": "Write and organize your notes",
276
+ "full_description": "Write notes and organize them in folders.\n\nFind saved notes with search."
277
+ }
278
+ ```
279
+
280
+ Use your actual app details. JSON represents paragraph breaks as `\n`; this
281
+ command translates supplied copy and does not infer features from Android XML.
282
+
283
+ ```bash
284
+ # Translate every bundled Google Play listing locale
285
+ android-localise store-listing --source listing.json --languages all
286
+ # Or select languages manually
287
+ android-localise store-listing --source listing.json --languages hi,es-ES,pt-BR
288
+ # Keep the original brand/app name and preview translations
289
+ android-localise store-listing --source listing.json --languages ja,zh-TW --keep-app-name --dry-run
290
+ # Explicitly refresh reviewed files when the source changes
291
+ android-localise store-listing --source listing.json --languages hi --overwrite
292
+ ```
293
+
294
+ Outputs are readable UTF-8 `store-listings/hi.json`, `store-listings/es-ES.json`,
295
+ etc., with the same three keys. Review the text and copy each field into its
296
+ language's Play Console listing; JSON is a local output format, not a Play
297
+ Console import file. The CLI does not upload or publish a listing.
298
+
299
+ | Flag | Description | Default |
300
+ |---|---|---|
301
+ | `--source` | UTF-8 JSON source listing | required |
302
+ | `--languages` | Play tags and/or `all`, e.g. `all,zu` or `hi-IN,es-ES` | required unless `--languages-file` supplies a list |
303
+ | `--languages-file` | UTF-8 comma/newline language list; combines with `--languages` | none |
304
+ | `--exclude-languages` | Remove exact normalized Play tags after selection | none |
305
+ | `--source-language` | Source listing language tag | `en-US` |
306
+ | `--output-dir` | Directory for `LOCALE.json` output | `store-listings` |
307
+ | `--keep-app-name` | Preserve the source app name exactly | off; name is localized with brand-preservation instructions |
308
+ | `--overwrite` | Replace existing locale files after validation | off; existing valid files are skipped |
309
+ | `--dry-run` | Generate, validate and display diffs without files/directories being written | off; API usage applies |
310
+ | `--provider` | `gemini`, `openai`, `anthropic`, `custom` | `gemini` |
311
+ | `--model` | Pin any supported model and disable fallbacks | provider default |
312
+ | `--api-key` | Explicit key override; omit for environment or saved Windows credentials | environment, then saved Windows key |
313
+ | `--base-url` | OpenAI-compatible endpoint; required for `custom` | provider endpoint |
314
+ | `--app-context` | Terminology context; source copy remains the source of facts | none |
315
+ | `--sleep` | Delay between requests, including correction/fallback requests | `5.0` seconds |
316
+ | `--timeout` | Per-response timeout; up to three attempts on timeout | `180` seconds |
317
+
318
+ **Validation:** source and translated fields must fit **30 / 80 / 4,000 characters**
319
+ respectively, as specified in [Google Play's product details guidance](https://support.google.com/googleplay/android-developer/answer/9859152).
320
+ Counts use Python Unicode code points, including spaces, punctuation, newlines
321
+ and any HTML markup, rather than UTF-8 bytes or visual glyphs. Check final counts
322
+ in Play Console too. Names and short descriptions must be single-line text.
323
+ Missing/extra/duplicate keys, blank fields, invalid JSON, unsupported controls
324
+ and unpaired surrogates are rejected. Overlong or otherwise invalid model output
325
+ gets up to **two correction requests**, with validation feedback; this can incur
326
+ additional API usage. Text is never blindly truncated. After validation the
327
+ complete listing is saved atomically. Rejected output preserves existing files;
328
+ other languages continue and any failure produces exit code 1.
329
+
330
+ Existing files are validated and skipped without translation API calls unless
331
+ `--overwrite` is set, including during a dry run. An invalid existing file fails
332
+ instead of being silently replaced; `--overwrite` explicitly regenerates it.
333
+ `--dry-run --overwrite` previews changes to existing files. Source/output path
334
+ collisions are rejected. Locale tags are syntax-checked and normalized (for
335
+ example `pt-br` becomes `pt-BR`); duplicate tags run once. This does not check
336
+ manual codes against Google Play's supported-language catalog. Choose tags available in your Console;
337
+ Android forms such as `values-hi`, `es-rES` and `b+zh+Hans` are not accepted here.
338
+
339
+ `--languages all` expands to the **86 store-listing locales** in
340
+ [Google Play's available-language list](https://support.google.com/googleplay/android-developer/answer/9844778?hl=en),
341
+ verified on **2026-10-02** and bundled with this release. It includes regional
342
+ variants and the source locale if present in the list. It does not fetch or
343
+ change the catalog at runtime. `all` is case-insensitive and can be combined with
344
+ manual additions. Use `--languages`, `--languages-file`, or both. Manual selection retains normalization and
345
+ duplicate removal. Each locale uses its own request, subject to existing-file
346
+ skips, correction/fallback requests and the configured delay. API usage applies
347
+ to all generated locales, including previews. Existing valid files still skip
348
+ unless `--overwrite` is set.
349
+
350
+ **Translation prompt:** includes the supplied [metadata policy](https://play.google.com/about/storelisting-promotional/metadata),
351
+ [Help Centre guidance](https://support.google.com/googleplay/android-developer/answer/9866151),
352
+ [programme policies](https://play.google.com/about/developer-content-policy) and
353
+ [advance-notice guidance](https://support.google.com/googleplay/android-developer/answer/6320428)
354
+ as publishing references, alongside text guidance reviewed on **2026-10-02**.
355
+ It asks for accurate, natural descriptions without invented claims, keyword
356
+ stuffing, misleading affiliations or anonymous testimonials. App names and
357
+ short descriptions avoid ranking/promotion language and decorative emoji;
358
+ short descriptions also avoid calls to action. Existing factual limitations,
359
+ URLs, brand names, required disclosures and full-description markup should be
360
+ preserved. Unsupported promotional wording should become factual copy.
361
+ These semantic rules are prompt instructions, not automated policy checks.
362
+ No policy pages are fetched by the CLI at runtime, so review the current linked
363
+ policies and translated claims before submitting. Advance notice remains a
364
+ separate developer step if eligible; no notice, permission or approval is implied.
365
+
366
+ **Manual check:** translate two languages, review all three fields with a native
367
+ speaker and check their counts in Play Console. Rerun to confirm existing files
368
+ skip, then use `--overwrite --dry-run` to review refreshes without saving.
369
+ Try a source name longer than 30 characters to confirm rejection before any
370
+ translation request.
371
+ For all-locale coverage, run `--languages all` into a separate output directory,
372
+ confirm 86 successful JSON outputs, then rerun and confirm 86 skips. Use a manual
373
+ list such as `hi-IN,es-ES` to confirm only those two outputs are generated.
374
+
375
+ ---
376
+
377
+ ### Composing translation commands
378
+
379
+ Both commands accept languages from the CLI, a UTF-8 file, or both. File entries
380
+ can be comma-separated or one per line, with blank lines and `#` comments.
381
+ For example, `languages.txt` can contain:
382
+
383
+ ```text
384
+ # Shared targets; conventional tags work in both commands
385
+ hi-IN
386
+ es-ES,pt-BR
387
+ zh-Hant-TW
388
+ ```
389
+
390
+ ```bash
391
+ # All bundled locales plus an extra, excluding exact regional variants
392
+ android-localise translate --languages all,zu --exclude-languages en-US,en-GB
393
+ android-localise store-listing --source listing.json --languages all,zu --exclude-languages en-US,en-GB
394
+ # Reuse a language file and add more targets
395
+ android-localise translate --languages-file languages.txt --languages de-DE --dry-run
396
+ android-localise store-listing --source listing.json --languages-file languages.txt --languages de-DE --dry-run
397
+ # Translate another source language into a separate Android resource directory
398
+ android-localise translate --source source/strings.xml --source-language fr-FR --output-dir translated/res --languages hi-IN,es-ES --skip-existing
399
+ ```
400
+
401
+ Ordering is CLI entries first, then file entries. `all` expands wherever it
402
+ appears; duplicates run once. XML equivalent qualifiers such as `es-ES`,
403
+ `es-rES` and `b+es+ES` run once, preserving the first selected folder spelling.
404
+ Exclusions apply after expansion and use exact locale identity: excluding `en`
405
+ does not exclude `en-US` or every English region. You can pass Android forms to
406
+ XML exclusions, and conventional tags to both commands. Listing language files
407
+ accept Play tags only. Manual tags are syntax-checked, not restricted to the
408
+ bundled Play catalog; verify Play Console supports any additional listing locale.
409
+ An empty final selection or invalid language/file fails before API calls or
410
+ folder creation. Source/output collisions, including linked source files, are
411
+ rejected. Provider, model, custom endpoint, context, delays, timeout and previews
412
+ remain independently configurable.
413
+
414
+ XML preservation choices are whole-file refresh (default), `--missing-only`
415
+ (fill missing resources) or `--skip-existing` (skip complete valid files).
416
+ The two preservation flags cannot be combined. Listing preservation remains
417
+ skip-by-default with explicit `--overwrite`. Preview flags can combine with any
418
+ valid mode and still use the provider for newly generated translations.
419
+ No setup, config file or language file is mandatory for existing commands.
420
+ `fix` and `verify` still use `--res-dir`; point them at a separate XML output
421
+ directory after placing the intended default source at `values/strings.xml` there.
422
+
423
+ Manual check: reuse one language file with both commands, combine `all` with an
424
+ extra locale and exclusions, preview before saving, and confirm existing files
425
+ are retained under the chosen preservation mode. Build the app and review the
426
+ actual translations; local validation does not prove linguistic quality.
427
+
428
+ ---
429
+
232
430
  ### `fix`
233
431
 
234
432
  ```bash
@@ -331,9 +529,72 @@ android-localise translate \
331
529
 
332
530
  ---
333
531
 
532
+ ## Save a key once on Windows
533
+
534
+ Run this yourself in your terminal:
535
+
536
+ ```bash
537
+ android-localise credentials set --provider gemini
538
+ ```
539
+
540
+ Enter your key at the hidden prompt. It is stored in **Windows Credential
541
+ Manager**, for your Windows user on this computer, and persists across terminal
542
+ and computer restarts. The CLI does not write a plaintext key file or modify
543
+ environment variables. Running `set` again replaces that provider's saved key.
544
+ There is no key argument or piped-input option for this command; it requires an
545
+ interactive terminal and refuses a prompt that cannot hide input.
546
+
547
+ Then you or an AI assistant can run ordinary commands without including a key:
548
+
549
+ ```bash
550
+ android-localise translate --languages hi,es
551
+ android-localise store-listing --source listing.json --languages hi-IN,es-ES
552
+ android-localise credentials status --provider gemini
553
+ android-localise credentials remove --provider gemini
554
+ ```
555
+
556
+ `status` reports only `saved` or `not saved`; no command displays the saved value.
557
+ `remove` deletes only this CLI's saved entry for that provider; it does not revoke
558
+ the provider key or clear environment-variable overrides. The same commands also
559
+ work with `python -m android_localisation credentials ...`.
560
+
561
+ | Argument | Description | Default |
562
+ |---|---|---|
563
+ | `set`, `status`, `remove` | Hidden entry, presence check, or deletion | required action |
564
+ | `--provider` | `gemini`, `openai` or `anthropic` | `gemini` |
565
+
566
+ Both translation commands use this precedence: `--api-key` → provider-specific
567
+ environment variable → `API_KEY` → saved Windows key. Existing overrides retain
568
+ their behavior; if an old environment key is set, saving a new key does not
569
+ override it. Saved OpenAI keys load only for its default endpoint; `custom`
570
+ providers and other `--base-url` endpoints continue using explicit keys or
571
+ environment variables. Saved keys are not automatically sent to custom hosts.
572
+ Provider requests reject HTTP redirects, so use a custom endpoint's final URL.
573
+ Gemini authentication uses a header rather than a URL query parameter, and
574
+ API/network error messages redact the key used for that request before display.
575
+
576
+ This keeps keys out of chat, command arguments and routine CLI output. It
577
+ **does not isolate secrets from an AI or other program with unrestricted access
578
+ under your Windows account**: Windows permits programs running as that user to
579
+ read their credentials. The key is also present in memory during an API request.
580
+ For stronger separation, use a restricted runner or separately secured proxy.
581
+ See [Microsoft's credential API documentation](https://learn.microsoft.com/en-us/windows/win32/api/wincred/nf-wincred-credreadw).
582
+
583
+ Saved-key commands are Windows-only, with no plaintext fallback. Other platforms
584
+ keep using environment variables or `--api-key`.
585
+
586
+ Manual check: save a key yourself, confirm input is hidden, open a new terminal
587
+ and check `status`. Run a small XML and listing preview without `--api-key`,
588
+ review the output, then remove the entry and confirm `not saved`. Ensure any key
589
+ environment overrides are absent when checking saved-key behavior.
590
+
591
+ ---
592
+
334
593
  ## Environment variables
335
594
 
336
- Set your API key as an env variable so you don't have to pass it every time:
595
+ Environment variables remain available on all platforms. For Windows saved
596
+ credentials, use the commands above instead of putting a key in shell history.
597
+ To use an environment variable:
337
598
 
338
599
  ```bash
339
600
  # macOS / Linux
@@ -415,13 +676,13 @@ PRs with cross-platform fixes and test notes are especially appreciated.
415
676
  | Topic | Detail |
416
677
  |---|---|
417
678
  | **Platform testing** | I test on **Windows only** — macOS and Linux need community verification (see [Platform support](#platform-support)) |
418
- | **Scope** | Reads `values/strings.xml` only. Strings, arrays and plurals within that file are checked; separate XML files are not scanned |
679
+ | **Scope** | `translate` reads one XML source, defaulting to `values/strings.xml`; `--source` can select another file. Output remains `strings.xml` per locale, with no automatic scan of other XML files. `store-listing` translates a separate three-field JSON listing |
419
680
  | **Plurals** | Preserves source quantities and item structure; does not generate target-language plural categories. Review plural completeness for each language |
420
- | **Overwrite** | Normal runs refresh whole files. `--missing-only` retains existing resources but does not detect source changes |
681
+ | **Overwrite** | `translate` refreshes whole files; `--missing-only` retains existing resources but does not detect source changes. `store-listing` skips existing files unless `--overwrite` is set |
421
682
  | **Folder scan** | Recognizes language-first and Android `b+` locale forms, with optional trailing qualifiers. MCC/MNC-prefixed resource folders are not scanned |
422
- | **Validation** | Requires source attributes, inline element order and formatting options to match. DTD/entity declarations are unsupported; checks do not replace Android compilation or language review |
423
- | **Large files** | One request per locale; no automatic batching or resume cache. Incomplete output is rejected |
424
- | **Network** | `translate` requires internet access to reach the LLM API (except local `custom` providers) |
683
+ | **Validation** | XML checks require source attributes, inline element order and formatting options to match; DTD/entity declarations are unsupported. Listing checks cover structure and field limits. Checks do not replace Android compilation, language review or policy review |
684
+ | **Large files** | `translate` sends one XML document per locale; no automatic batching or resume cache. Listings have bounded field lengths and may use correction requests. Incomplete provider output is rejected |
685
+ | **Network** | `translate` and `store-listing` require access to the LLM API (local `custom` providers can work offline; disable update checks for fully offline use) |
425
686
  | **JDK** | `verify` requires `javac` on your PATH |
426
687
 
427
688
  ---
@@ -430,7 +691,7 @@ PRs with cross-platform fixes and test notes are especially appreciated.
430
691
 
431
692
  | Problem | What to try |
432
693
  |---|---|
433
- | `Could not find English strings.xml` | Check `--res-dir` points to your `res/` folder and `values/strings.xml` exists |
694
+ | `Could not find source XML` | Check `--source`, or ensure `--res-dir` contains `values/strings.xml` |
434
695
  | `No locale directories found` | Add `--languages hi,es,fr` or create `values-<lang>/` folders manually |
435
696
  | API auth errors | Confirm your key env var or `--api-key` matches the `--provider` |
436
697
  | Resource validation fails | Read the named resource error; check source/target keys, attributes, placeholders and markup. Existing files are retained |