mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
langtool: Let import-single create the key in en_US.ini too
It skipped the reference file, so adding a new string meant running add-new-key-value first just to get the key into en_US.ini (and, as a side effect, the English text into all 46 other files whether they were about to be translated or not). Now an en_US line in the imported file is treated like any other language, minus the "AI translated" comment, since that one is the string the others were translated from rather than a translation. So the workflow is one command plus validate. Languages left out of the import simply don't get the key, and fall back to the English string at runtime - copy-missing-lines is still there if you want the placeholder written out. Instructions in AGENTS.md and the /add-string command updated to match. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_0164UKoXpz9r155TRfQsoc3H
This commit is contained in:
1 parent
10bfda59ee
commit
a1d205539c
3 files changed
+57
-46
No files matched your search
@@ -13,11 +13,7 @@ Add and/or translate a PPSSPP UI string.
|
||||
Follow the workflow in AGENTS.md under "Translated UI strings (assets/lang)". Run langtool from
|
||||
`Tools/langtool`:
|
||||
|
||||
1. If an English string was given above:
|
||||
`cargo run -- add-new-key-value "$1" "$2" "$3"`
|
||||
That adds the key to every language file with the English text as a placeholder.
|
||||
|
||||
2. **Work out what the string actually means before translating it.** This is the part the tool's
|
||||
1. **Work out what the string actually means before translating it.** This is the part the tool's
|
||||
own AI commands can't do, and the whole reason you're doing this instead of them:
|
||||
- Grep the C++ for the key to find the call site. What widget is it? A button, a checkbox
|
||||
label, a tooltip, a error message?
|
||||
@@ -29,29 +25,33 @@ Follow the workflow in AGENTS.md under "Translated UI strings (assets/lang)". Ru
|
||||
|
||||
Say briefly what you found before you start translating.
|
||||
|
||||
3. Write the translations to a scratch file outside the repo, in this shape:
|
||||
2. Write the translations to a scratch file outside the repo, in this shape:
|
||||
|
||||
```ini
|
||||
[Single]
|
||||
en_US = Test string
|
||||
sv_SE = Teststräng
|
||||
lt-LT = Testeilutė
|
||||
```
|
||||
|
||||
One line per language, named after the ini file minus the extension (`lt-LT`, `he_IL_invert`,
|
||||
`zh_TW`, ...). No trailing `# comments` on those lines, they'd end up inside the translation.
|
||||
Placeholders like `%1` and `%d` have to appear verbatim in the translation, in whatever position
|
||||
the target language needs them.
|
||||
`zh_TW`, ...), plus an `en_US` line carrying the English string itself if you were given one -
|
||||
that's what creates the key in `en_US.ini`. No trailing `# comments` on those lines, they'd end
|
||||
up inside the translation. Placeholders like `%1` and `%d` have to appear verbatim in the
|
||||
translation, in whatever position the target language needs them.
|
||||
|
||||
**If you don't know a language well enough to be confident, leave it out.** The English string
|
||||
stays as the fallback, which is normal and fine - much better than a confident guess that nobody
|
||||
in the project can read well enough to catch.
|
||||
**If you don't know a language well enough to be confident, leave it out.** A key that's missing
|
||||
from a language file falls back to the English string at runtime, which is normal and fine - much
|
||||
better than a confident guess that nobody in the project can read well enough to catch.
|
||||
|
||||
4. `cargo run -- import-single <scratch-file> "$1" "$2"`
|
||||
3. `cargo run -- import-single <scratch-file> "$1" "$2"`
|
||||
|
||||
Note this overwrites any existing value for that key, so if the key already had human
|
||||
translations, check what you're about to replace first.
|
||||
translations, check what you're about to replace first. The section has to exist already.
|
||||
|
||||
5. `cargo run -- validate` - always, at the end. It must print `Found 0 problems.`
|
||||
4. `cargo run -- validate` - always, at the end. It must print `Found 0 problems.`
|
||||
|
||||
Finally, report which languages you translated and which you skipped and why, and leave the changes
|
||||
uncommitted for review unless asked otherwise.
|
||||
uncommitted for review unless asked otherwise. If you want the languages you skipped to carry the
|
||||
English string as a visible placeholder rather than just falling back to it, that's
|
||||
`cargo run -- copy-missing-lines`.
|
||||
@@ -189,28 +189,32 @@ the ~47 files**, and don't run the AI commands in `Tools/langtool` either - you
|
||||
which its fixed prompt can't. Do the translating yourself and let the tool do the file surgery. Run it
|
||||
from `Tools/langtool`:
|
||||
|
||||
1. `cargo run -- add-new-key-value <Section> "<Key>" "<English string>"` adds the key to every file,
|
||||
English everywhere. (Skip if the key already exists and you're only filling in translations.)
|
||||
2. Work out what the string actually means before translating it: find where it's used in the C++,
|
||||
1. Work out what the string actually means before translating it: find where it's used in the C++,
|
||||
what any `%1`/`%d` placeholders get substituted with, how long it can be without breaking the
|
||||
layout, and how neighboring keys are already phrased in each language (that's your style guide).
|
||||
Then write a scratch file, one line per language, named after the ini file minus the extension:
|
||||
2. Write a scratch file, one line per language, named after the ini file minus the extension, with
|
||||
the English string under `en_US`:
|
||||
```ini
|
||||
[Single]
|
||||
en_US = Test string
|
||||
sv_SE = Teststräng
|
||||
lt-LT = Testeilutė
|
||||
```
|
||||
No trailing `# comments` on those lines, they'd end up inside the translation. Placeholders have to
|
||||
survive verbatim. If you don't know a language well enough, leave it out - it keeps the English
|
||||
string, which is the normal fallback, and that's much better than a confident guess.
|
||||
3. `cargo run -- import-single <scratch-file> <Section> "<Key>"` writes them in, tagged
|
||||
`# AI translated`. Note that it overwrites existing values for that key, so take care with keys
|
||||
that already have human translations.
|
||||
survive verbatim. If you don't know a language well enough, leave it out - a key that's missing from
|
||||
a language file falls back to the English string at runtime, which is much better than a confident
|
||||
guess.
|
||||
3. `cargo run -- import-single <scratch-file> <Section> "<Key>"` writes them all in, including a new
|
||||
key in en_US.ini, tagged `# AI translated` except for the en_US line, which is the string the rest
|
||||
were translated from. Note it overwrites existing values for that key, so take care with keys that
|
||||
already have human translations, and that the section has to exist already - langtool won't create
|
||||
one.
|
||||
4. `cargo run -- validate` at the end, always. It checks that placeholders survived and exits
|
||||
non-zero if anything is off.
|
||||
|
||||
The other mechanical jobs (renaming and moving keys, sorting sections, copying missing lines to all
|
||||
files) are langtool commands too - prefer them over editing the ini files by hand.
|
||||
Optionally follow up with `cargo run -- copy-missing-lines` to give the languages you skipped the
|
||||
English string as a placeholder. The other mechanical jobs (renaming and moving keys, sorting
|
||||
sections) are langtool commands too - prefer them over editing the ini files by hand.
|
||||
|
||||
## Headless and unittest builds
|
||||
|
||||
|
||||
+26
-19
@@ -1032,31 +1032,38 @@ fn execute_command(cmd: Command, ai: Option<&Ai>, dry_run: bool, verbose: bool)
|
||||
ref section,
|
||||
ref key,
|
||||
} => {
|
||||
if !is_reference {
|
||||
let lang_id = filename.strip_suffix(".ini").unwrap();
|
||||
if let Some(single_section) = &single_ini_section {
|
||||
if let Some(target_section) = target_ini.get_section_mut(section) {
|
||||
if let Some(single_line) = single_section.get_line(lang_id) {
|
||||
if let Some(value) = line_value(&single_line) {
|
||||
println!(
|
||||
"Inserting value {value} for key {key} in section {section} in {target_ini_filename}"
|
||||
);
|
||||
if !target_section.insert_line_if_missing(&format!(
|
||||
"{key} = {value} # AI translated"
|
||||
)) {
|
||||
// Didn't insert it, so it exists. We need to replace it.
|
||||
target_section.set_value(key, value, Some("AI translated"));
|
||||
}
|
||||
let lang_id = filename.strip_suffix(".ini").unwrap();
|
||||
// en_US is in here too, if the file has a line for it - that one is the English
|
||||
// string the others were translated from, not a translation, so no comment on it.
|
||||
let comment = if is_reference {
|
||||
None
|
||||
} else {
|
||||
Some("AI translated")
|
||||
};
|
||||
if let Some(single_section) = &single_ini_section {
|
||||
if let Some(target_section) = target_ini.get_section_mut(section) {
|
||||
if let Some(single_line) = single_section.get_line(lang_id) {
|
||||
if let Some(value) = line_value(&single_line) {
|
||||
println!(
|
||||
"Inserting value {value} for key {key} in section {section} in {target_ini_filename}"
|
||||
);
|
||||
let line = match comment {
|
||||
Some(comment) => format!("{key} = {value} # {comment}"),
|
||||
None => format!("{key} = {value}"),
|
||||
};
|
||||
if !target_section.insert_line_if_missing(&line) {
|
||||
// Didn't insert it, so it exists. We need to replace it.
|
||||
target_section.set_value(key, value, comment);
|
||||
}
|
||||
} else {
|
||||
println!("No lang_id {lang_id} in single section");
|
||||
}
|
||||
} else {
|
||||
println!("No section {section} in {target_ini_filename}");
|
||||
println!("No lang_id {lang_id} in single section");
|
||||
}
|
||||
} else {
|
||||
println!("No section {section} in {filename}");
|
||||
println!("No section {section} in {target_ini_filename}");
|
||||
}
|
||||
} else {
|
||||
println!("No section {section} in {filename}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user