mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(i18n): regenerate derived app catalogs inside native:i18n:sync (#110454)
Rewriting apps/.i18n/native-source.json without regenerating the derived Android/Apple artifacts lands a stale iOS catalog and turns the repo-wide apple/android i18n checks red for every PR (this is how main broke after recent app-string additions: the inventory and translations were committed while Localizable.xcstrings was not regenerated). native-app-i18n.ts sync --write now chains syncAndroidAppI18n and a new exported syncAppleAppI18n (catalog + InfoPlist strings) so one command leaves the whole i18n tree consistent. The shared locale list moves to scripts/native-i18n-locales.ts to break the import cycle between the inventory scanner's top-level CLI await and the derived generators.
This commit is contained in:
committed by
GitHub
parent
0d822a3495
commit
e5ac755681
@@ -3,7 +3,7 @@ import { readdir, readFile, writeFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { expectDefined } from "../packages/normalization-core/src/expect.js";
|
||||
import { NATIVE_I18N_LOCALES } from "./native-app-i18n.ts";
|
||||
import { NATIVE_I18N_LOCALES } from "./native-i18n-locales.ts";
|
||||
|
||||
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT = path.resolve(HERE, "..");
|
||||
|
||||
@@ -858,6 +858,20 @@ export async function syncIosCatalog(write: boolean): Promise<AppleCatalogBuild>
|
||||
return build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerates every Apple derived artifact (iOS catalog, contradiction report,
|
||||
* InfoPlist strings). Shared by this CLI and native-app-i18n's sync so the
|
||||
* inventory can never be rewritten without its derived catalogs.
|
||||
*/
|
||||
export async function syncAppleAppI18n(): Promise<{
|
||||
build: AppleCatalogBuild;
|
||||
infoPlistFiles: number;
|
||||
}> {
|
||||
const build = await syncIosCatalog(true);
|
||||
const infoPlistFiles = await syncIosInfoPlist(true);
|
||||
return { build, infoPlistFiles };
|
||||
}
|
||||
|
||||
export async function checkAppleAppI18n() {
|
||||
await validateRuntimeInterpolationPaths();
|
||||
for (const [sourcePath, contracts] of Object.entries(LOCALIZED_WRAPPER_CONTRACTS)) {
|
||||
@@ -956,8 +970,7 @@ if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.ar
|
||||
if (command === "check") {
|
||||
await checkAppleAppI18n();
|
||||
} else if (command === "sync-ios" && flag === "--write") {
|
||||
const build = await syncIosCatalog(true);
|
||||
const infoPlistFiles = await syncIosInfoPlist(true);
|
||||
const { build, infoPlistFiles } = await syncAppleAppI18n();
|
||||
process.stdout.write(
|
||||
`apple-app-i18n: synced iOS catalog and ${infoPlistFiles} InfoPlist files; contradictions=${build.contradictions.length}\n`,
|
||||
);
|
||||
|
||||
+18
-23
@@ -5,32 +5,11 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
import pMap from "p-map";
|
||||
import { expectDefined } from "../packages/normalization-core/src/expect.js";
|
||||
import { translateNativeEntries } from "./control-ui-i18n.ts";
|
||||
import { NATIVE_I18N_LOCALES } from "./native-i18n-locales.ts";
|
||||
|
||||
type NativeI18nSurface = "android" | "apple";
|
||||
|
||||
export const NATIVE_I18N_LOCALES = [
|
||||
"zh-CN",
|
||||
"zh-TW",
|
||||
"pt-BR",
|
||||
"de",
|
||||
"es",
|
||||
"ja-JP",
|
||||
"ko",
|
||||
"fr",
|
||||
"hi",
|
||||
"ar",
|
||||
"it",
|
||||
"tr",
|
||||
"uk",
|
||||
"id",
|
||||
"pl",
|
||||
"th",
|
||||
"vi",
|
||||
"nl",
|
||||
"fa",
|
||||
"ru",
|
||||
"sv",
|
||||
] as const;
|
||||
export { NATIVE_I18N_LOCALES };
|
||||
|
||||
export type NativeI18nEntry = {
|
||||
id: string;
|
||||
@@ -1642,6 +1621,22 @@ async function main() {
|
||||
if (parsed.locale) {
|
||||
await syncNativeLocale(parsed.locale, entries);
|
||||
}
|
||||
if (parsed.command === "sync" && parsed.write) {
|
||||
// The inventory and native/*.json feed the generated Android/Apple app
|
||||
// artifacts. Regenerate them in the same write; a sync that stops at the
|
||||
// inventory lands stale derived catalogs and turns the repo-wide
|
||||
// android/apple i18n checks red. Lazy imports keep check/locale-only runs
|
||||
// from loading the derived generators.
|
||||
const [{ syncAndroidAppI18n }, { syncAppleAppI18n }] = await Promise.all([
|
||||
import("./android-app-i18n.ts"),
|
||||
import("./apple-app-i18n.ts"),
|
||||
]);
|
||||
await syncAndroidAppI18n();
|
||||
const apple = await syncAppleAppI18n();
|
||||
process.stdout.write(
|
||||
`native-app-i18n: synced derived artifacts (android, iOS catalog, ${apple.infoPlistFiles} InfoPlist files); contradictions=${apple.build.contradictions.length}\n`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Shared native-app locale list. Lives outside native-app-i18n.ts so the
|
||||
* derived generators (android-app-i18n, apple-app-i18n) can import it without
|
||||
* creating a cycle with native-app-i18n's top-level CLI await, which chains
|
||||
* those generators after rewriting the inventory.
|
||||
*/
|
||||
export const NATIVE_I18N_LOCALES = [
|
||||
"zh-CN",
|
||||
"zh-TW",
|
||||
"pt-BR",
|
||||
"de",
|
||||
"es",
|
||||
"ja-JP",
|
||||
"ko",
|
||||
"fr",
|
||||
"hi",
|
||||
"ar",
|
||||
"it",
|
||||
"tr",
|
||||
"uk",
|
||||
"id",
|
||||
"pl",
|
||||
"th",
|
||||
"vi",
|
||||
"nl",
|
||||
"fa",
|
||||
"ru",
|
||||
"sv",
|
||||
] as const;
|
||||
Reference in New Issue
Block a user