From 191ac978b0dcc0ab7bfccba9de5d9a26d5e81766 Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Fri, 2 Oct 2026 11:48:49 +0100 Subject: [PATCH] Document supported_locales for Mobile 4.6 mobile-air #369 adds a supported_locales config key. It decides which languages an app offers in the Android per-app language picker, the iOS Preferred Language setting and the App Store listing. Adds a Localization page under Digging Deeper, a short reference in Configuration, and updates the permission string sections for apps and plugins. The upgrade guide gets a 4.6 entry because translated iOS permission strings now need their locale declared. Co-Authored-By: Claude Opus 5.5 --- config/docs.php | 2 +- .../mobile/4/digging-deeper/localization.md | 144 ++++++++++++++++++ .../mobile/4/getting-started/configuration.md | 33 ++++ .../mobile/4/getting-started/upgrade-guide.md | 28 ++++ .../4/plugins/permissions-dependencies.md | 9 ++ 5 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 resources/views/docs/mobile/4/digging-deeper/localization.md diff --git a/config/docs.php b/config/docs.php index 5468e4447..fa3fabd09 100644 --- a/config/docs.php +++ b/config/docs.php @@ -59,7 +59,7 @@ 1 => ['1.0', '1.1'], 2 => ['2.0'], 3 => ['3.0', '3.1', '3.2', '3.3'], - 4 => ['4.0', '4.1', '4.2', '4.3', '4.4', '4.5'], + 4 => ['4.0', '4.1', '4.2', '4.3', '4.4', '4.5', '4.6'], ], ], diff --git a/resources/views/docs/mobile/4/digging-deeper/localization.md b/resources/views/docs/mobile/4/digging-deeper/localization.md new file mode 100644 index 000000000..03203993d --- /dev/null +++ b/resources/views/docs/mobile/4/digging-deeper/localization.md @@ -0,0 +1,144 @@ +--- +title: Localization +order: 95 +--- + +## Overview + + + +Tell NativePHP which languages your app supports and your users can pick one for your app, separately from the +language of their device. On Android your app appears in the system's per-app language picker. On iOS it gets a +Preferred Language setting, and the App Store lists those languages on your product page. + +You declare the languages in one config key. Translating your app still happens the Laravel way, with `lang/` files +and `__()`. + +## Declaring your languages + +List the languages in the `supported_locales` array in `config/nativephp.php`: + +```php +'supported_locales' => ['fr', 'nl', 'zh-Hans'], +``` + +Your app's own language, `config('app.locale')`, is always included and always comes first, so users can switch back +to it. You don't list it yourself. If `app.locale` is `en`, the config above gives your app four languages: `en`, +`fr`, `nl` and `zh-Hans`. + +- Entries are BCP 47 codes such as `nl`, `pt-BR` or `zh-Hans`. Laravel-style `nl_NL` is accepted and becomes `nl-NL`. +- Duplicates are dropped, ignoring case. +- Invalid entries are skipped with a [build warning](#build-warnings). +- An empty array means your app supports one language, `app.locale`. + + + +## What your users see + +### Android + +On Android 13 and later, your app appears in the system's per-app language picker under Settings → Apps → your app → +Language. Before 4.6, a NativePHP app could only follow the system language. + +To do this, NativePHP writes `res/xml/locales_config.xml` and points your app's manifest at it. This only happens when +your app supports two or more languages. With one language the app is left untouched and no Language entry shows. + +### iOS + +NativePHP declares the languages as `CFBundleLocalizations` in your app's `Info.plist`. Your app then gets a Preferred +Language row under Settings → your app. + + + +### App Store + +The App Store lists exactly these languages on your app's product page. + +## Translating your app + +Listing a locale only lets the user pick it. Translating your app is still your job. Add +[Laravel language files](https://laravel.com/docs/localization) as you would in any Laravel app, either +`lang/fr/...` or `lang/fr.json`, and use `__()` for your strings. + +## Using the chosen language + +NativePHP doesn't set Laravel's locale for you. The language the user picked is reported by +[`Device::getInfo()`](../the-basics/device#device-info) in the `language` field, as a BCP 47 tag such as `fr-FR`. + +Read it early, for example in `AppServiceProvider::boot()`, and pass it to `App::setLocale()`: + +```php +use Illuminate\Support\Facades\App; +use Native\Mobile\Facades\Device; + +// AppServiceProvider::boot() +$info = Device::getInfo(); // JSON string, or null when not on a device + +if ($info !== null) { + $language = json_decode($info, true)['language'] ?? ''; // 'fr-FR' + $locale = explode('-', $language)[0]; // 'fr' + + if (in_array($locale, ['fr', 'nl'], true)) { + App::setLocale($locale); + } +} +``` + +The tag includes a region (`fr-FR`), while a Laravel `lang/` folder is usually just `fr`, so the example keeps only the +language part. It also only switches to a locale the app has translations for. Anything else stays on `app.locale`. + + + +## Permission strings + +On iOS, translated permission strings are only written for the languages your app supports. That covers your own +`permission_localizations` and the translations your plugins ship. Entries for any other locale are skipped. + +A plugin can bring translations for its permission strings, but it can't add a language to your app. See +[Localizing iOS Permission Strings](../getting-started/configuration#localizing-ios-permission-strings). + +## Build warnings + +NativePHP prints these warnings while it builds your app, during `native:run` and when you package it. + +``` +Translations exist for de but nativephp.supported_locales does not list them, so the app will not offer them +``` + +Your `lang/` directory has a folder or `.json` file for a locale that isn't in `supported_locales`. Add the locale to +the list if you want users to be able to pick it. `lang/vendor` is ignored. + +NativePHP doesn't scan `lang/` to decide which languages ship. The list stays explicit, so a translation you've only +just started isn't offered to users by accident. + +``` +Ignoring invalid locale 'english' in nativephp.supported_locales +``` + +An entry in `supported_locales` isn't a locale code. The entry is skipped and the rest of the list is used. + +## Removing a language + +Take the locale out of `supported_locales` and rebuild. You don't need to run `native:install --force`. + +- **Android:** the locale is removed from the locale config. If only one language is left, NativePHP deletes the locale + config and takes the attribute back out of the manifest. +- **iOS:** `CFBundleLocalizations` is rewritten and the `.lproj` folder NativePHP generated for that language is + deleted. An `.lproj` folder holding anything besides the generated `InfoPlist.strings` is left alone. diff --git a/resources/views/docs/mobile/4/getting-started/configuration.md b/resources/views/docs/mobile/4/getting-started/configuration.md index 3ae07adf7..33c8b0b72 100644 --- a/resources/views/docs/mobile/4/getting-started/configuration.md +++ b/resources/views/docs/mobile/4/getting-started/configuration.md @@ -312,6 +312,30 @@ Set your Apple Developer Team ID for code signing: This is typically detected from your installed certificates, but you can override it here. Find your Team ID in your Apple Developer account under Membership details. +## Supported Locales + + + +The `supported_locales` array lists the languages your app supports: + +```php +'supported_locales' => ['fr', 'nl', 'zh-Hans'], +``` + +On Android 13 and later, this puts your app in the system's per-app language picker. On iOS, it gives your app a +Preferred Language setting and decides which languages the App Store lists on your product page. + +- `config('app.locale')` is always included and always first, so users can switch back to it. You don't list it + yourself. +- Entries are BCP 47 codes (`nl`, `pt-BR`, `zh-Hans`). Laravel-style `nl_NL` is accepted and becomes `nl-NL`. +- Duplicates are dropped, ignoring case. Invalid entries are skipped with a build warning. +- An empty array means your app supports one language, `app.locale`. +- The list is read at build time, so the base language of a build is whatever `APP_LOCALE` was on the machine that + built it. + +Listing a locale only lets the user pick it. Translating your app is still up to you and your `lang/` files. See +[Localization](../digging-deeper/localization) for the full guide. + ## iOS Permission Strings Plugins declare their own iOS `Info.plist` usage descriptions through their manifests (see @@ -343,6 +367,8 @@ are shown at runtime by app code, so there's no equivalent override. ## Localizing iOS Permission Strings + + The strings in `permissions` go straight into `Info.plist`, which iOS treats as the **development region** fallback. Users running their device in another language see those same strings unless you ship a localized override. @@ -351,6 +377,8 @@ Add per-locale strings under `permission_localizations`. Each key is a BCP 47 lo (e.g. `nl`, `fr`, `zh-Hans`, `pt-BR`) and its value mirrors the `permissions` shape: ```php +'supported_locales' => ['nl', 'fr'], + 'permissions' => [ 'NSCameraUsageDescription' => 'Used to take a profile photo.', ], @@ -369,6 +397,9 @@ At build time NativePHP writes one `{locale}.lproj/InfoPlist.strings` file per l and registers the locale with the Xcode project so it ships with the app. iOS then picks the right string at runtime based on the user's preferred language, falling back to the value in `permissions`. +Strings are only written for locales your app supports: the ones in [`supported_locales`](#supported-locales), plus +`app.locale`. Entries for any other locale are skipped. +