From 690ed564419291ca6e832dc69b53061300075b62 Mon Sep 17 00:00:00 2001 From: joshavant <830519+joshavant@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:56:15 -0500 Subject: [PATCH] fix(ios): preserve localized app display names --- apps/.i18n/native-source.json | 16 ------- .../ActivityWidget/ar.lproj/InfoPlist.strings | 2 +- .../ActivityWidget/de.lproj/InfoPlist.strings | 2 +- .../ActivityWidget/es.lproj/InfoPlist.strings | 2 +- .../ActivityWidget/fa.lproj/InfoPlist.strings | 2 +- .../ActivityWidget/fr.lproj/InfoPlist.strings | 2 +- .../ActivityWidget/hi.lproj/InfoPlist.strings | 2 +- .../ActivityWidget/id.lproj/InfoPlist.strings | 2 +- .../ActivityWidget/it.lproj/InfoPlist.strings | 2 +- .../ActivityWidget/ja.lproj/InfoPlist.strings | 2 +- .../ActivityWidget/ko.lproj/InfoPlist.strings | 2 +- .../ActivityWidget/nl.lproj/InfoPlist.strings | 2 +- .../ActivityWidget/pl.lproj/InfoPlist.strings | 2 +- .../pt-BR.lproj/InfoPlist.strings | 2 +- .../ActivityWidget/ru.lproj/InfoPlist.strings | 2 +- .../ActivityWidget/sv.lproj/InfoPlist.strings | 2 +- .../ActivityWidget/th.lproj/InfoPlist.strings | 2 +- .../ActivityWidget/tr.lproj/InfoPlist.strings | 2 +- .../ActivityWidget/uk.lproj/InfoPlist.strings | 2 +- .../ActivityWidget/vi.lproj/InfoPlist.strings | 2 +- .../zh-Hans.lproj/InfoPlist.strings | 2 +- .../zh-Hant.lproj/InfoPlist.strings | 2 +- .../ShareExtension/ar.lproj/InfoPlist.strings | 2 +- .../ShareExtension/de.lproj/InfoPlist.strings | 2 +- .../ShareExtension/es.lproj/InfoPlist.strings | 2 +- .../ShareExtension/fa.lproj/InfoPlist.strings | 2 +- .../ShareExtension/fr.lproj/InfoPlist.strings | 2 +- .../ShareExtension/hi.lproj/InfoPlist.strings | 2 +- .../ShareExtension/id.lproj/InfoPlist.strings | 2 +- .../ShareExtension/it.lproj/InfoPlist.strings | 2 +- .../ShareExtension/ja.lproj/InfoPlist.strings | 2 +- .../ShareExtension/ko.lproj/InfoPlist.strings | 2 +- .../ShareExtension/nl.lproj/InfoPlist.strings | 2 +- .../ShareExtension/pl.lproj/InfoPlist.strings | 2 +- .../pt-BR.lproj/InfoPlist.strings | 2 +- .../ShareExtension/ru.lproj/InfoPlist.strings | 2 +- .../ShareExtension/sv.lproj/InfoPlist.strings | 2 +- .../ShareExtension/th.lproj/InfoPlist.strings | 2 +- .../ShareExtension/tr.lproj/InfoPlist.strings | 2 +- .../ShareExtension/uk.lproj/InfoPlist.strings | 2 +- .../ShareExtension/vi.lproj/InfoPlist.strings | 2 +- .../zh-Hans.lproj/InfoPlist.strings | 2 +- .../zh-Hant.lproj/InfoPlist.strings | 2 +- apps/ios/Sources/Info.plist | 2 +- apps/ios/Sources/ar.lproj/InfoPlist.strings | 1 - apps/ios/Sources/de.lproj/InfoPlist.strings | 1 - apps/ios/Sources/es.lproj/InfoPlist.strings | 1 - apps/ios/Sources/fa.lproj/InfoPlist.strings | 1 - apps/ios/Sources/fr.lproj/InfoPlist.strings | 1 - apps/ios/Sources/hi.lproj/InfoPlist.strings | 1 - apps/ios/Sources/id.lproj/InfoPlist.strings | 1 - apps/ios/Sources/it.lproj/InfoPlist.strings | 1 - apps/ios/Sources/ja.lproj/InfoPlist.strings | 1 - apps/ios/Sources/ko.lproj/InfoPlist.strings | 1 - apps/ios/Sources/nl.lproj/InfoPlist.strings | 1 - apps/ios/Sources/pl.lproj/InfoPlist.strings | 1 - .../ios/Sources/pt-BR.lproj/InfoPlist.strings | 1 - apps/ios/Sources/ru.lproj/InfoPlist.strings | 1 - apps/ios/Sources/sv.lproj/InfoPlist.strings | 1 - apps/ios/Sources/th.lproj/InfoPlist.strings | 1 - apps/ios/Sources/tr.lproj/InfoPlist.strings | 1 - apps/ios/Sources/uk.lproj/InfoPlist.strings | 1 - apps/ios/Sources/vi.lproj/InfoPlist.strings | 1 - .../Sources/zh-Hans.lproj/InfoPlist.strings | 1 - .../Sources/zh-Hant.lproj/InfoPlist.strings | 1 - apps/ios/WatchApp/ar.lproj/InfoPlist.strings | 1 - apps/ios/WatchApp/de.lproj/InfoPlist.strings | 1 - apps/ios/WatchApp/es.lproj/InfoPlist.strings | 1 - apps/ios/WatchApp/fa.lproj/InfoPlist.strings | 1 - apps/ios/WatchApp/fr.lproj/InfoPlist.strings | 1 - apps/ios/WatchApp/hi.lproj/InfoPlist.strings | 1 - apps/ios/WatchApp/id.lproj/InfoPlist.strings | 1 - apps/ios/WatchApp/it.lproj/InfoPlist.strings | 1 - apps/ios/WatchApp/ja.lproj/InfoPlist.strings | 1 - apps/ios/WatchApp/ko.lproj/InfoPlist.strings | 1 - apps/ios/WatchApp/nl.lproj/InfoPlist.strings | 1 - apps/ios/WatchApp/pl.lproj/InfoPlist.strings | 1 - .../WatchApp/pt-BR.lproj/InfoPlist.strings | 1 - apps/ios/WatchApp/ru.lproj/InfoPlist.strings | 1 - apps/ios/WatchApp/sv.lproj/InfoPlist.strings | 1 - apps/ios/WatchApp/th.lproj/InfoPlist.strings | 1 - apps/ios/WatchApp/tr.lproj/InfoPlist.strings | 1 - apps/ios/WatchApp/uk.lproj/InfoPlist.strings | 1 - apps/ios/WatchApp/vi.lproj/InfoPlist.strings | 1 - .../WatchApp/zh-Hans.lproj/InfoPlist.strings | 1 - .../WatchApp/zh-Hant.lproj/InfoPlist.strings | 1 - apps/ios/project.yml | 4 +- scripts/apple-app-i18n.ts | 7 +--- scripts/ios-validate-app-store-ipa.sh | 17 ++++++++ scripts/native-app-i18n.ts | 28 ++++++++++--- test/scripts/apple-app-i18n.test.ts | 28 +++++++++++-- .../ios-validate-app-store-ipa.test.ts | 42 +++++++++++++++++++ test/scripts/native-app-i18n.test.ts | 19 +++++++++ 93 files changed, 170 insertions(+), 119 deletions(-) diff --git a/apps/.i18n/native-source.json b/apps/.i18n/native-source.json index 4b924fe24e61..1375fb9ad9ba 100644 --- a/apps/.i18n/native-source.json +++ b/apps/.i18n/native-source.json @@ -15073,14 +15073,6 @@ "surface": "android", "id": "native.android.709aff840be1f167" }, - { - "kind": "plist-string", - "line": 8, - "path": "apps/ios/ActivityWidget/Info.plist", - "source": "OpenClaw Activity", - "surface": "apple", - "id": "native.apple.8f741d09cc1d5495" - }, { "kind": "ui-call", "line": 18, @@ -15201,14 +15193,6 @@ "surface": "apple", "id": "native.apple.18d4f8a4eea7f930" }, - { - "kind": "plist-string", - "line": 8, - "path": "apps/ios/ShareExtension/Info.plist", - "source": "OpenClaw Share", - "surface": "apple", - "id": "native.apple.9168fcd110c3019a" - }, { "kind": "conditional-branch", "line": 236, diff --git a/apps/ios/ActivityWidget/ar.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/ar.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/ar.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/ar.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/de.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/de.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/de.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/de.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/es.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/es.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/es.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/es.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/fa.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/fa.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/fa.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/fa.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/fr.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/fr.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/fr.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/fr.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/hi.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/hi.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/hi.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/hi.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/id.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/id.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/id.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/id.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/it.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/it.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/it.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/it.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/ja.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/ja.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/ja.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/ja.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/ko.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/ko.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/ko.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/ko.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/nl.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/nl.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/nl.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/nl.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/pl.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/pl.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/pl.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/pl.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/pt-BR.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/pt-BR.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/pt-BR.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/pt-BR.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/ru.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/ru.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/ru.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/ru.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/sv.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/sv.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/sv.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/sv.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/th.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/th.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/th.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/th.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/tr.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/tr.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/tr.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/tr.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/uk.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/uk.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/uk.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/uk.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/vi.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/vi.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/vi.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/vi.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/zh-Hans.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/zh-Hans.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/zh-Hans.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/zh-Hans.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ActivityWidget/zh-Hant.lproj/InfoPlist.strings b/apps/ios/ActivityWidget/zh-Hant.lproj/InfoPlist.strings index 85fde909ccc8..8b137891791f 100644 --- a/apps/ios/ActivityWidget/zh-Hant.lproj/InfoPlist.strings +++ b/apps/ios/ActivityWidget/zh-Hant.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Activity"; + diff --git a/apps/ios/ShareExtension/ar.lproj/InfoPlist.strings b/apps/ios/ShareExtension/ar.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/ar.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/ar.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/de.lproj/InfoPlist.strings b/apps/ios/ShareExtension/de.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/de.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/de.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/es.lproj/InfoPlist.strings b/apps/ios/ShareExtension/es.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/es.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/es.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/fa.lproj/InfoPlist.strings b/apps/ios/ShareExtension/fa.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/fa.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/fa.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/fr.lproj/InfoPlist.strings b/apps/ios/ShareExtension/fr.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/fr.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/fr.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/hi.lproj/InfoPlist.strings b/apps/ios/ShareExtension/hi.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/hi.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/hi.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/id.lproj/InfoPlist.strings b/apps/ios/ShareExtension/id.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/id.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/id.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/it.lproj/InfoPlist.strings b/apps/ios/ShareExtension/it.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/it.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/it.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/ja.lproj/InfoPlist.strings b/apps/ios/ShareExtension/ja.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/ja.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/ja.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/ko.lproj/InfoPlist.strings b/apps/ios/ShareExtension/ko.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/ko.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/ko.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/nl.lproj/InfoPlist.strings b/apps/ios/ShareExtension/nl.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/nl.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/nl.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/pl.lproj/InfoPlist.strings b/apps/ios/ShareExtension/pl.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/pl.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/pl.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/pt-BR.lproj/InfoPlist.strings b/apps/ios/ShareExtension/pt-BR.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/pt-BR.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/pt-BR.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/ru.lproj/InfoPlist.strings b/apps/ios/ShareExtension/ru.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/ru.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/ru.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/sv.lproj/InfoPlist.strings b/apps/ios/ShareExtension/sv.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/sv.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/sv.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/th.lproj/InfoPlist.strings b/apps/ios/ShareExtension/th.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/th.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/th.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/tr.lproj/InfoPlist.strings b/apps/ios/ShareExtension/tr.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/tr.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/tr.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/uk.lproj/InfoPlist.strings b/apps/ios/ShareExtension/uk.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/uk.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/uk.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/vi.lproj/InfoPlist.strings b/apps/ios/ShareExtension/vi.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/vi.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/vi.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/zh-Hans.lproj/InfoPlist.strings b/apps/ios/ShareExtension/zh-Hans.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/zh-Hans.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/zh-Hans.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/ShareExtension/zh-Hant.lproj/InfoPlist.strings b/apps/ios/ShareExtension/zh-Hant.lproj/InfoPlist.strings index 20e0bdb147c3..8b137891791f 100644 --- a/apps/ios/ShareExtension/zh-Hant.lproj/InfoPlist.strings +++ b/apps/ios/ShareExtension/zh-Hant.lproj/InfoPlist.strings @@ -1 +1 @@ -"CFBundleDisplayName" = "OpenClaw Share"; + diff --git a/apps/ios/Sources/Info.plist b/apps/ios/Sources/Info.plist index b4f03acc8321..d38f8231741a 100644 --- a/apps/ios/Sources/Info.plist +++ b/apps/ios/Sources/Info.plist @@ -9,7 +9,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - $(OPENCLAW_APP_DISPLAY_NAME) + OpenClaw CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconName diff --git a/apps/ios/Sources/ar.lproj/InfoPlist.strings b/apps/ios/Sources/ar.lproj/InfoPlist.strings index 838ce2c5a8df..0e3c530b11aa 100644 --- a/apps/ios/Sources/ar.lproj/InfoPlist.strings +++ b/apps/ios/Sources/ar.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "يستخدم OpenClaw تقويماتك لعرض الأحداث وسياق الجدولة عند تفعيل الوصول إلى التقويم."; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/de.lproj/InfoPlist.strings b/apps/ios/Sources/de.lproj/InfoPlist.strings index b86d40499756..d2169c480e39 100644 --- a/apps/ios/Sources/de.lproj/InfoPlist.strings +++ b/apps/ios/Sources/de.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "OpenClaw verwendet Ihre Kalender, um Ereignisse und Planungskontext anzuzeigen, wenn Sie den Kalenderzugriff aktivieren."; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/es.lproj/InfoPlist.strings b/apps/ios/Sources/es.lproj/InfoPlist.strings index 57f71f74efe8..dfd06e740a8f 100644 --- a/apps/ios/Sources/es.lproj/InfoPlist.strings +++ b/apps/ios/Sources/es.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "OpenClaw usa tus calendarios para mostrar eventos y contexto de programación cuando activas el acceso al calendario."; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/fa.lproj/InfoPlist.strings b/apps/ios/Sources/fa.lproj/InfoPlist.strings index b1283cdc64eb..fb18b9213afe 100644 --- a/apps/ios/Sources/fa.lproj/InfoPlist.strings +++ b/apps/ios/Sources/fa.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "OpenClaw از تقویم‌های شما استفاده می‌کند تا وقتی دسترسی به تقویم را فعال می‌کنید، رویدادها و زمینهٔ زمان‌بندی را نشان دهد."; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/fr.lproj/InfoPlist.strings b/apps/ios/Sources/fr.lproj/InfoPlist.strings index 9dccf0d4c1bd..a18dbd76cd98 100644 --- a/apps/ios/Sources/fr.lproj/InfoPlist.strings +++ b/apps/ios/Sources/fr.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "OpenClaw utilise vos calendriers pour afficher les événements et le contexte de planification lorsque vous activez l’accès au calendrier."; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/hi.lproj/InfoPlist.strings b/apps/ios/Sources/hi.lproj/InfoPlist.strings index 0abc633c6821..158f6cbabb88 100644 --- a/apps/ios/Sources/hi.lproj/InfoPlist.strings +++ b/apps/ios/Sources/hi.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "जब आप कैलेंडर एक्सेस सक्षम करते हैं, तो OpenClaw इवेंट और शेड्यूलिंग संदर्भ दिखाने के लिए आपके कैलेंडर का उपयोग करता है."; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/id.lproj/InfoPlist.strings b/apps/ios/Sources/id.lproj/InfoPlist.strings index 96f54d25da48..84c65fb7023a 100644 --- a/apps/ios/Sources/id.lproj/InfoPlist.strings +++ b/apps/ios/Sources/id.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "OpenClaw menggunakan kalender Anda untuk menampilkan acara dan konteks penjadwalan saat Anda mengaktifkan akses kalender."; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/it.lproj/InfoPlist.strings b/apps/ios/Sources/it.lproj/InfoPlist.strings index d338d7732762..88636261d628 100644 --- a/apps/ios/Sources/it.lproj/InfoPlist.strings +++ b/apps/ios/Sources/it.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "OpenClaw usa i tuoi calendari per mostrare eventi e contesto di pianificazione quando abiliti l'accesso al calendario."; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/ja.lproj/InfoPlist.strings b/apps/ios/Sources/ja.lproj/InfoPlist.strings index de497d0898b1..7d43aa5ebed3 100644 --- a/apps/ios/Sources/ja.lproj/InfoPlist.strings +++ b/apps/ios/Sources/ja.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "OpenClawは、カレンダーへのアクセスを有効にしたときに、イベントとスケジュールのコンテキストを表示するためにカレンダーを使用します。"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/ko.lproj/InfoPlist.strings b/apps/ios/Sources/ko.lproj/InfoPlist.strings index 0b5afe50d6fc..223792605e45 100644 --- a/apps/ios/Sources/ko.lproj/InfoPlist.strings +++ b/apps/ios/Sources/ko.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "캘린더 접근을 활성화하면 OpenClaw가 캘린더를 사용하여 이벤트와 일정 컨텍스트를 표시합니다."; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/nl.lproj/InfoPlist.strings b/apps/ios/Sources/nl.lproj/InfoPlist.strings index 43a121270031..324362f43ab5 100644 --- a/apps/ios/Sources/nl.lproj/InfoPlist.strings +++ b/apps/ios/Sources/nl.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "OpenClaw gebruikt je agenda’s om gebeurtenissen en planningscontext te tonen wanneer je agendatoegang inschakelt."; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/pl.lproj/InfoPlist.strings b/apps/ios/Sources/pl.lproj/InfoPlist.strings index 4c2572fe3dab..85402261c2eb 100644 --- a/apps/ios/Sources/pl.lproj/InfoPlist.strings +++ b/apps/ios/Sources/pl.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "OpenClaw używa Twoich kalendarzy do wyświetlania wydarzeń i kontekstu planowania, gdy włączysz dostęp do kalendarza."; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/pt-BR.lproj/InfoPlist.strings b/apps/ios/Sources/pt-BR.lproj/InfoPlist.strings index ea48ce050697..54964a9854d4 100644 --- a/apps/ios/Sources/pt-BR.lproj/InfoPlist.strings +++ b/apps/ios/Sources/pt-BR.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "O OpenClaw usa seus calendários para mostrar eventos e contexto de agendamento quando você ativa o acesso ao calendário."; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/ru.lproj/InfoPlist.strings b/apps/ios/Sources/ru.lproj/InfoPlist.strings index bf989875ab05..9c64ccca2199 100644 --- a/apps/ios/Sources/ru.lproj/InfoPlist.strings +++ b/apps/ios/Sources/ru.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "OpenClaw использует ваши календари, чтобы показывать события и контекст расписания, когда вы включаете доступ к календарю."; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/sv.lproj/InfoPlist.strings b/apps/ios/Sources/sv.lproj/InfoPlist.strings index d7eec5ec0795..11bdd82a5d2a 100644 --- a/apps/ios/Sources/sv.lproj/InfoPlist.strings +++ b/apps/ios/Sources/sv.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "OpenClaw använder dina kalendrar för att visa händelser och schemaläggningssammanhang när du aktiverar kalenderåtkomst."; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/th.lproj/InfoPlist.strings b/apps/ios/Sources/th.lproj/InfoPlist.strings index 206a1760c0ad..6b86eeb65f75 100644 --- a/apps/ios/Sources/th.lproj/InfoPlist.strings +++ b/apps/ios/Sources/th.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "OpenClaw ใช้ปฏิทินของคุณเพื่อแสดงกิจกรรมและบริบทการจัดกำหนดการเมื่อคุณเปิดใช้งานการเข้าถึงปฏิทิน"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/tr.lproj/InfoPlist.strings b/apps/ios/Sources/tr.lproj/InfoPlist.strings index dede337c925c..13172c117ced 100644 --- a/apps/ios/Sources/tr.lproj/InfoPlist.strings +++ b/apps/ios/Sources/tr.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "OpenClaw, takvim erişimini etkinleştirdiğinizde etkinlikleri ve planlama bağlamını göstermek için takvimlerinizi kullanır."; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/uk.lproj/InfoPlist.strings b/apps/ios/Sources/uk.lproj/InfoPlist.strings index e6f94a08115d..7e1b54474acf 100644 --- a/apps/ios/Sources/uk.lproj/InfoPlist.strings +++ b/apps/ios/Sources/uk.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "OpenClaw використовує ваші календарі, щоб показувати події та контекст планування, коли ви надаєте доступ до календаря."; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/vi.lproj/InfoPlist.strings b/apps/ios/Sources/vi.lproj/InfoPlist.strings index 55be62688c70..20c031cf9013 100644 --- a/apps/ios/Sources/vi.lproj/InfoPlist.strings +++ b/apps/ios/Sources/vi.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "OpenClaw sử dụng lịch của bạn để hiển thị sự kiện và ngữ cảnh lên lịch khi bạn bật quyền truy cập lịch."; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/zh-Hans.lproj/InfoPlist.strings b/apps/ios/Sources/zh-Hans.lproj/InfoPlist.strings index 8f389ac2ab0e..cfae48f272f3 100644 --- a/apps/ios/Sources/zh-Hans.lproj/InfoPlist.strings +++ b/apps/ios/Sources/zh-Hans.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "当你启用日历访问权限时,OpenClaw 会使用你的日历来显示事件和日程安排上下文。"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/Sources/zh-Hant.lproj/InfoPlist.strings b/apps/ios/Sources/zh-Hant.lproj/InfoPlist.strings index f7da9dff1bee..51359394701e 100644 --- a/apps/ios/Sources/zh-Hant.lproj/InfoPlist.strings +++ b/apps/ios/Sources/zh-Hant.lproj/InfoPlist.strings @@ -1,4 +1,3 @@ -"CFBundleDisplayName" = "$(OPENCLAW_APP_DISPLAY_NAME)"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ "NSCalendarsFullAccessUsageDescription" = "OpenClaw 會在你啟用行事曆存取權限時,使用你的行事曆來顯示事件與排程情境。"; /* OpenClaw source: "OpenClaw uses your calendars to show events and scheduling context when you enable calendar access." */ diff --git a/apps/ios/WatchApp/ar.lproj/InfoPlist.strings b/apps/ios/WatchApp/ar.lproj/InfoPlist.strings index 1609e0803a7b..0aaf64d59f32 100644 --- a/apps/ios/WatchApp/ar.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/ar.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "يربط OpenClaw ساعة Apple Watch هذه مباشرةً بـ Gateway الخاص بك على الشبكات المحلية الموثوقة."; diff --git a/apps/ios/WatchApp/de.lproj/InfoPlist.strings b/apps/ios/WatchApp/de.lproj/InfoPlist.strings index 0cb24a7b1029..6480c34f420e 100644 --- a/apps/ios/WatchApp/de.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/de.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "OpenClaw verbindet diese Apple Watch in vertrauenswürdigen lokalen Netzwerken direkt mit Ihrem Gateway."; diff --git a/apps/ios/WatchApp/es.lproj/InfoPlist.strings b/apps/ios/WatchApp/es.lproj/InfoPlist.strings index c784984b9ed1..099adc2615bc 100644 --- a/apps/ios/WatchApp/es.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/es.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "OpenClaw conecta este Apple Watch directamente a tu Gateway en redes locales de confianza."; diff --git a/apps/ios/WatchApp/fa.lproj/InfoPlist.strings b/apps/ios/WatchApp/fa.lproj/InfoPlist.strings index f3a211554e3e..aed5b047bf9b 100644 --- a/apps/ios/WatchApp/fa.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/fa.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "OpenClaw این Apple Watch را در شبکه‌های محلی مورد اعتماد مستقیماً به Gateway شما متصل می‌کند."; diff --git a/apps/ios/WatchApp/fr.lproj/InfoPlist.strings b/apps/ios/WatchApp/fr.lproj/InfoPlist.strings index d9210d8c7383..50bc85467499 100644 --- a/apps/ios/WatchApp/fr.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/fr.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "OpenClaw connecte cette Apple Watch directement à votre Gateway sur les réseaux locaux de confiance."; diff --git a/apps/ios/WatchApp/hi.lproj/InfoPlist.strings b/apps/ios/WatchApp/hi.lproj/InfoPlist.strings index 98e852773315..83ca100488b4 100644 --- a/apps/ios/WatchApp/hi.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/hi.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "OpenClaw इस Apple Watch को विश्वसनीय लोकल नेटवर्क पर सीधे आपके Gateway से कनेक्ट करता है।"; diff --git a/apps/ios/WatchApp/id.lproj/InfoPlist.strings b/apps/ios/WatchApp/id.lproj/InfoPlist.strings index 7db156181b7a..254f18b764b9 100644 --- a/apps/ios/WatchApp/id.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/id.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "OpenClaw menyambungkan Apple Watch ini langsung ke Gateway Anda di jaringan lokal tepercaya."; diff --git a/apps/ios/WatchApp/it.lproj/InfoPlist.strings b/apps/ios/WatchApp/it.lproj/InfoPlist.strings index e0011a9c6fb2..2cee5a88c3de 100644 --- a/apps/ios/WatchApp/it.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/it.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "OpenClaw connette questo Apple Watch direttamente al tuo Gateway su reti locali attendibili."; diff --git a/apps/ios/WatchApp/ja.lproj/InfoPlist.strings b/apps/ios/WatchApp/ja.lproj/InfoPlist.strings index 22aecad88cc6..605819077fa2 100644 --- a/apps/ios/WatchApp/ja.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/ja.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "OpenClaw は信頼できるローカルネットワーク上で、この Apple Watch を Gateway に直接接続します。"; diff --git a/apps/ios/WatchApp/ko.lproj/InfoPlist.strings b/apps/ios/WatchApp/ko.lproj/InfoPlist.strings index 21ef63bf0ec4..17c01d5b7872 100644 --- a/apps/ios/WatchApp/ko.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/ko.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "OpenClaw는 신뢰할 수 있는 로컬 네트워크에서 이 Apple Watch를 Gateway에 직접 연결합니다."; diff --git a/apps/ios/WatchApp/nl.lproj/InfoPlist.strings b/apps/ios/WatchApp/nl.lproj/InfoPlist.strings index 1ef6fb2cbbe2..715ed267089b 100644 --- a/apps/ios/WatchApp/nl.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/nl.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "OpenClaw verbindt deze Apple Watch rechtstreeks met je Gateway op vertrouwde lokale netwerken."; diff --git a/apps/ios/WatchApp/pl.lproj/InfoPlist.strings b/apps/ios/WatchApp/pl.lproj/InfoPlist.strings index 584ed04b2807..e65362062ec6 100644 --- a/apps/ios/WatchApp/pl.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/pl.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "OpenClaw łączy ten Apple Watch bezpośrednio z Twoim Gateway w zaufanych sieciach lokalnych."; diff --git a/apps/ios/WatchApp/pt-BR.lproj/InfoPlist.strings b/apps/ios/WatchApp/pt-BR.lproj/InfoPlist.strings index 1d04320951ca..bff19ee619b9 100644 --- a/apps/ios/WatchApp/pt-BR.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/pt-BR.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "O OpenClaw conecta este Apple Watch diretamente ao seu Gateway em redes locais confiáveis."; diff --git a/apps/ios/WatchApp/ru.lproj/InfoPlist.strings b/apps/ios/WatchApp/ru.lproj/InfoPlist.strings index 710b171527a5..c31eaa9a03af 100644 --- a/apps/ios/WatchApp/ru.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/ru.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "OpenClaw подключает эти Apple Watch напрямую к вашему Gateway в доверенных локальных сетях."; diff --git a/apps/ios/WatchApp/sv.lproj/InfoPlist.strings b/apps/ios/WatchApp/sv.lproj/InfoPlist.strings index 2c7ea8afc2c1..022f767620b5 100644 --- a/apps/ios/WatchApp/sv.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/sv.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "OpenClaw ansluter denna Apple Watch direkt till din Gateway på betrodda lokala nätverk."; diff --git a/apps/ios/WatchApp/th.lproj/InfoPlist.strings b/apps/ios/WatchApp/th.lproj/InfoPlist.strings index 88875c47fa8b..4343e8a84715 100644 --- a/apps/ios/WatchApp/th.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/th.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "OpenClaw เชื่อมต่อ Apple Watch นี้เข้ากับ Gateway ของคุณโดยตรงบนเครือข่ายในพื้นที่ที่เชื่อถือได้"; diff --git a/apps/ios/WatchApp/tr.lproj/InfoPlist.strings b/apps/ios/WatchApp/tr.lproj/InfoPlist.strings index af4444a6fcc3..425c3e2da8f4 100644 --- a/apps/ios/WatchApp/tr.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/tr.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "OpenClaw, bu Apple Watch'u güvenilir yerel ağlarda doğrudan Gateway'inize bağlar."; diff --git a/apps/ios/WatchApp/uk.lproj/InfoPlist.strings b/apps/ios/WatchApp/uk.lproj/InfoPlist.strings index 997b437303fe..cd71b583bd36 100644 --- a/apps/ios/WatchApp/uk.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/uk.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "OpenClaw підключає цей Apple Watch безпосередньо до вашого Gateway в довірених локальних мережах."; diff --git a/apps/ios/WatchApp/vi.lproj/InfoPlist.strings b/apps/ios/WatchApp/vi.lproj/InfoPlist.strings index 79d78d369e29..8f33e3e3260a 100644 --- a/apps/ios/WatchApp/vi.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/vi.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "OpenClaw kết nối Apple Watch này trực tiếp với Gateway của bạn trên các mạng cục bộ đáng tin cậy."; diff --git a/apps/ios/WatchApp/zh-Hans.lproj/InfoPlist.strings b/apps/ios/WatchApp/zh-Hans.lproj/InfoPlist.strings index 56aced421b2b..3a0cf65ba81a 100644 --- a/apps/ios/WatchApp/zh-Hans.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/zh-Hans.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "在受信任的本地网络上,OpenClaw 将此 Apple Watch 直接连接到您的 Gateway。"; diff --git a/apps/ios/WatchApp/zh-Hant.lproj/InfoPlist.strings b/apps/ios/WatchApp/zh-Hant.lproj/InfoPlist.strings index 6190d7781596..41b76408fb72 100644 --- a/apps/ios/WatchApp/zh-Hant.lproj/InfoPlist.strings +++ b/apps/ios/WatchApp/zh-Hant.lproj/InfoPlist.strings @@ -1,3 +1,2 @@ -"CFBundleDisplayName" = "OpenClaw"; /* OpenClaw source: "OpenClaw connects this Apple Watch directly to your Gateway on trusted local networks." */ "NSLocalNetworkUsageDescription" = "OpenClaw 會在受信任的本機網路上將此 Apple Watch 直接連線到您的 Gateway。"; diff --git a/apps/ios/project.yml b/apps/ios/project.yml index 20f0e473cf5e..66f6dead6d68 100644 --- a/apps/ios/project.yml +++ b/apps/ios/project.yml @@ -114,7 +114,6 @@ targets: CODE_SIGN_STYLE: "$(OPENCLAW_CODE_SIGN_STYLE)" DEVELOPMENT_TEAM: "$(OPENCLAW_DEVELOPMENT_TEAM)" OPENCLAW_ACTIVE_APP_GROUP_ID: "$(OPENCLAW_APP_GROUP_ID)" - OPENCLAW_APP_DISPLAY_NAME: OpenClaw OPENCLAW_URL_SCHEME: openclaw PRODUCT_BUNDLE_IDENTIFIER: "$(OPENCLAW_APP_BUNDLE_ID)" PROVISIONING_PROFILE_SPECIFIER: "$(OPENCLAW_APP_PROFILE)" @@ -129,7 +128,6 @@ targets: ASSETCATALOG_COMPILER_APPICON_NAME: AppIconDebug CODE_SIGN_STYLE: Automatic OPENCLAW_ACTIVE_APP_GROUP_ID: "$(OPENCLAW_DEBUG_APP_GROUP_ID)" - OPENCLAW_APP_DISPLAY_NAME: OpenClaw OPENCLAW_CODE_SIGN_ENTITLEMENTS: Sources/OpenClaw.entitlements OPENCLAW_APNS_ENTITLEMENT_ENVIRONMENT: development OPENCLAW_URL_SCHEME: openclaw-debug @@ -145,7 +143,7 @@ targets: info: path: Sources/Info.plist properties: - CFBundleDisplayName: "$(OPENCLAW_APP_DISPLAY_NAME)" + CFBundleDisplayName: OpenClaw CFBundleIconName: "$(ASSETCATALOG_COMPILER_APPICON_NAME)" CFBundleURLTypes: - CFBundleURLName: ai.openclawfoundation.app diff --git a/scripts/apple-app-i18n.ts b/scripts/apple-app-i18n.ts index 207893c68697..614588efee1f 100644 --- a/scripts/apple-app-i18n.ts +++ b/scripts/apple-app-i18n.ts @@ -481,9 +481,7 @@ function parseInfoPlistStrings(source: string): Array<{ key: string; source: str key: decodeXml(match[1] ?? ""), source: decodeXml(match[2] ?? ""), })) - .filter( - (entry) => entry.key === "CFBundleDisplayName" || entry.key.endsWith("UsageDescription"), - ); + .filter((entry) => entry.key.endsWith("UsageDescription")); } type InfoPlistTranslation = { @@ -855,9 +853,6 @@ async function syncIosInfoPlist(write: boolean): Promise { const existing = parseStringsFile(existingSource ?? ""); const artifact = translations.find((candidate) => candidate.locale === locale); const lines = sourceEntries.map(({ key, source }) => { - if (key === "CFBundleDisplayName") { - return `${stringsLiteral(key)} = ${stringsLiteral(source)};`; - } const sourceId = sourceIds.get([target.sourcePath, source].join("\u0000")); if (!sourceId) { throw new Error(`missing native InfoPlist source id for ${target.sourcePath}:${key}`); diff --git a/scripts/ios-validate-app-store-ipa.sh b/scripts/ios-validate-app-store-ipa.sh index 91eab6896a43..e248c1cbd338 100755 --- a/scripts/ios-validate-app-store-ipa.sh +++ b/scripts/ios-validate-app-store-ipa.sh @@ -219,11 +219,28 @@ assert_build_provenance() { fi } +assert_localized_plists_resolve_build_settings() { + local localized_plist + local rendered + while IFS= read -r -d '' localized_plist; do + if ! rendered="$("${PLUTIL_BIN}" -convert xml1 -o - "${localized_plist}" 2>/dev/null)"; then + echo "Invalid IPA: could not read localized plist ${localized_plist#"${app_path}/"}." >&2 + exit 1 + fi + if grep -Eq '\$\([A-Za-z0-9_.-]+\)|\$\{[A-Za-z0-9_.-]+\}' <<<"${rendered}"; then + echo "Invalid IPA: unresolved build setting in localized plist ${localized_plist#"${app_path}/"}." >&2 + exit 1 + fi + done < <(find "${app_path}" -type f -path "*.lproj/InfoPlist.strings" -print0) +} + assert_plist_string "${info_plist}" "CFBundleIdentifier" "${EXPECTED_BUNDLE_ID}" "bundle identifier mismatch" +assert_plist_string "${info_plist}" "CFBundleDisplayName" "OpenClaw" "display name mismatch" assert_plist_string "${info_plist}" "OpenClawPushMode" "${EXPECTED_PUSH_MODE}" "push mode mismatch" assert_plist_nonempty_string "${info_plist}" "NSHealthShareUsageDescription" "Health share usage description" assert_plist_nonempty_string "${info_plist}" "NSHealthUpdateUsageDescription" "Health update usage description" assert_build_provenance +assert_localized_plists_resolve_build_settings assert_plist_empty_or_absent "${info_plist}" "OpenClawPushRelayBaseURL" "push relay URL override" assert_plist_key_absent "${info_plist}" "OpenClawPushTransport" "legacy push transport" assert_plist_key_absent "${info_plist}" "OpenClawPushDistribution" "legacy push distribution" diff --git a/scripts/native-app-i18n.ts b/scripts/native-app-i18n.ts index b1f7f75bb726..df9889193d92 100644 --- a/scripts/native-app-i18n.ts +++ b/scripts/native-app-i18n.ts @@ -166,7 +166,9 @@ const APPLE_BUILTIN_UI_CALLS = new Set([ "Toggle", "searchable", ]); -const APPLE_PLIST_STRINGS = /([\s\S]*?)<\/string>/gu; +const APPLE_PLIST_KEYED_STRINGS = /([^<]+)<\/key>\s*([\s\S]*?)<\/string>/gu; +// macOS uses this legacy privacy key instead of the *UsageDescription suffix. +const APPLE_LOCALIZABLE_DESCRIPTION_KEYS = new Set(["NSScreenCaptureDescription"]); const GENERATED_PATH_RE = /(?:^|[\\/])(?:build|\.gradle|\.build|DerivedData)(?:$|[\\/])/u; const EXCLUDED_PATH_RE = /(?:^|[\\/])(?:Tests?|UITests?|test|Preview(?:s)?)(?:$|[\\/])/u; const EXCLUDED_FILE_RE = /(?:Tests?|UITests?|Previews?|Testing)\.(?:swift|kt|kts)$/u; @@ -196,6 +198,19 @@ function isAsciiAlphaNumeric(character: string): boolean { ); } +function decodeXml(value: string): string { + return value + .replaceAll(""", '"') + .replaceAll("'", "'") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll("&", "&"); +} + +function isLocalizableApplePlistKey(key: string): boolean { + return key.endsWith("UsageDescription") || APPLE_LOCALIZABLE_DESCRIPTION_KEYS.has(key); +} + export function isConditionalBranchIdentifier(source: string): boolean { let index = 0; while (index < source.length && isAsciiLowercaseLetter(source.charAt(index))) { @@ -1058,15 +1073,18 @@ export function extractNativeI18nCandidates( } } if (surface === "apple" && repoPath.endsWith(".plist")) { - for (const match of source.matchAll(APPLE_PLIST_STRINGS)) { - if (match[1]) { + for (const match of source.matchAll(APPLE_PLIST_KEYED_STRINGS)) { + const key = match[1]; + const value = match[2]; + if (key && isLocalizableApplePlistKey(key) && value) { + const valueOffset = (match.index ?? 0) + match[0].indexOf(value); addCandidate( entries, surface, repoPath, - match[1], + decodeXml(value), "plist-string", - lineNumber(source, match.index ?? 0), + lineNumber(source, valueOffset), ); } } diff --git a/test/scripts/apple-app-i18n.test.ts b/test/scripts/apple-app-i18n.test.ts index a134221b6b62..c542d41a2a94 100644 --- a/test/scripts/apple-app-i18n.test.ts +++ b/test/scripts/apple-app-i18n.test.ts @@ -1,4 +1,4 @@ -import { mkdtemp, readFile, rm } from "node:fs/promises"; +import { mkdtemp, readFile, readdir, rm } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { describe, expect, it } from "vitest"; @@ -464,7 +464,7 @@ describe("Apple app i18n catalogs", () => { ]); }); - it("generates InfoPlist localizations for every shipped iOS target", async () => { + it("generates only localized usage descriptions for every shipped iOS target", async () => { const french = await readFile("apps/ios/Sources/fr.lproj/InfoPlist.strings", "utf8"); const watchChinese = await readFile( "apps/ios/WatchApp/zh-Hans.lproj/InfoPlist.strings", @@ -483,8 +483,28 @@ describe("Apple app i18n catalogs", () => { expect(french).toContain('"NSMicrophoneUsageDescription" = '); expect(french).toContain('"NSHealthUpdateUsageDescription" = '); expect(watchChinese).toContain('"NSLocalNetworkUsageDescription" = '); - expect(shareGerman).toContain('"CFBundleDisplayName" = "OpenClaw Share";'); - expect(activityJapanese).toContain('"CFBundleDisplayName" = "OpenClaw Activity";'); + expect(shareGerman.trim()).toBe(""); + expect(activityJapanese.trim()).toBe(""); + + for (const root of [ + "apps/ios/Sources", + "apps/ios/WatchApp", + "apps/ios/ShareExtension", + "apps/ios/ActivityWidget", + ]) { + const localeDirs = (await readdir(root, { withFileTypes: true })).filter( + (entry) => entry.isDirectory() && entry.name.endsWith(".lproj"), + ); + expect(localeDirs).toHaveLength(APPLE_I18N_LOCALES.length); + for (const localeDir of localeDirs) { + const localizedPlist = await readFile( + path.join(root, localeDir.name, "InfoPlist.strings"), + "utf8", + ); + expect(localizedPlist).not.toContain("CFBundleDisplayName"); + expect(localizedPlist).not.toMatch(/\$\([^)]*\)|\$\{[^}]*\}/u); + } + } }); it("refreshes InfoPlist copy from translations for the current source", () => { diff --git a/test/scripts/ios-validate-app-store-ipa.test.ts b/test/scripts/ios-validate-app-store-ipa.test.ts index e62e6bd3796b..a1909d4f5c40 100644 --- a/test/scripts/ios-validate-app-store-ipa.test.ts +++ b/test/scripts/ios-validate-app-store-ipa.test.ts @@ -128,6 +128,10 @@ function writeFakePlutil(filePath: string): void { filePath, `#!/usr/bin/env node const { readFileSync } = require("node:fs"); +if (process.argv[2] === "-convert" && process.argv[3] === "xml1") { + process.stdout.write(readFileSync(process.argv[process.argv.length - 1], "utf8")); + process.exit(0); +} const extractIndex = process.argv.indexOf("-extract"); const expectIndex = process.argv.indexOf("-expect"); if (extractIndex < 0 || expectIndex < 0 || process.argv[expectIndex + 1] !== "string") process.exit(2); @@ -209,6 +213,8 @@ async function writeValidFixture( buildCommit?: string; buildTimestamp?: string; healthUpdateUsage?: boolean | string | null; + displayName?: string; + localizedDisplayName?: string; pushMode?: string; legacyKey?: boolean; } = {}, @@ -230,6 +236,7 @@ async function writeValidFixture( const infoBody = [ plistString("CFBundleIdentifier", "ai.openclawfoundation.app"), + plistString("CFBundleDisplayName", options.displayName ?? "OpenClaw"), plistString("OpenClawGitCommit", options.buildCommit ?? BUILD_COMMIT), plistString("OpenClawBuildTimestamp", options.buildTimestamp ?? BUILD_TIMESTAMP), plistString("OpenClawPushMode", options.pushMode ?? "appStore"), @@ -249,6 +256,17 @@ async function writeValidFixture( options.legacyKey ? plistString("OpenClawPushRelayProfile", "production") : "", ].join(""); writeFileSync(path.join(appDir, "Info.plist"), plist(infoBody), "utf8"); + const localizedDir = path.join(appDir, "de.lproj"); + mkdirSync(localizedDir, { recursive: true }); + writeFileSync( + path.join(localizedDir, "InfoPlist.strings"), + plist( + options.localizedDisplayName === undefined + ? plistString("NSCameraUsageDescription", "OpenClaw verwendet die Kamera.") + : plistString("CFBundleDisplayName", options.localizedDisplayName), + ), + "utf8", + ); writeFileSync(path.join(appDir, "embedded.mobileprovision"), "fixture profile", "utf8"); const entitlementsPath = path.join(fixturesDir, "entitlements.plist"); @@ -406,6 +424,30 @@ describe("scripts/ios-validate-app-store-ipa.sh", () => { expect(result.stderr).toContain("Health update usage description must be a non-empty string"); }); + it("rejects an IPA with the wrong canonical display name", async () => { + const root = mkdtempSync(path.join(os.tmpdir(), "openclaw-ios-ipa-")); + tempDirs.push(root); + const fixture = await writeValidFixture(root, { displayName: "OpenClaw Debug" }); + + const result = runValidator(fixture); + + expect(result.ok).toBe(false); + expect(result.stderr).toContain("display name mismatch"); + }); + + it("rejects unresolved build settings in localized plist resources", async () => { + const root = mkdtempSync(path.join(os.tmpdir(), "openclaw-ios-ipa-")); + tempDirs.push(root); + const fixture = await writeValidFixture(root, { + localizedDisplayName: "$(OPENCLAW_APP_DISPLAY_NAME)", + }); + + const result = runValidator(fixture); + + expect(result.ok).toBe(false); + expect(result.stderr).toContain("unresolved build setting in localized plist"); + }); + it("rejects a non-string Health update purpose value", async () => { const root = mkdtempSync(path.join(os.tmpdir(), "openclaw-ios-ipa-")); tempDirs.push(root); diff --git a/test/scripts/native-app-i18n.test.ts b/test/scripts/native-app-i18n.test.ts index b544fa5b6a3b..71037f5a264d 100644 --- a/test/scripts/native-app-i18n.test.ts +++ b/test/scripts/native-app-i18n.test.ts @@ -275,6 +275,25 @@ describe("native app i18n inventory", () => { expect(entries.map((entry) => entry.source)).toEqual(["Gateway ready"]); }); + it("extracts only localizable usage descriptions from Apple plists", () => { + const entries = extractNativeI18nCandidates( + "apple", + "apps/ios/Fixture/Info.plist", + ` + CFBundleDisplayName + OpenClaw Fixture + NSCameraUsageDescription + OpenClaw uses the camera to scan setup codes & documents. + OpenClawFixtureValue + Runtime configuration value + `, + ); + + expect(entries.map((entry) => entry.source)).toEqual([ + "OpenClaw uses the camera to scan setup codes & documents.", + ]); + }); + it("respects non-translatable Android collections and retains lowercase choices", () => { const entries = extractNativeI18nCandidates( "android",