mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-14 18:26:11 -04:00
Compare commits
79
Commits
v5.2.2-rc1
...
v5.2.5-rc0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a41bef21b5 | ||
|
|
91b49536b7 | ||
|
|
8690072ee2 | ||
|
|
92c829c7e6 | ||
|
|
1c67a78130 | ||
|
|
7a64a23d1e | ||
|
|
e2fcbbfdfd | ||
|
|
29639cdcd1 | ||
|
|
d8a6ef2286 | ||
|
|
e68927595c | ||
|
|
aa928de265 | ||
|
|
3662904d75 | ||
|
|
cec36268e0 | ||
|
|
5895ccbc27 | ||
|
|
798ac32ec9 | ||
|
|
6ed0bf8257 | ||
|
|
39a6c3c89f | ||
|
|
2ba90e1d18 | ||
|
|
92dac661c4 | ||
|
|
7712b18388 | ||
|
|
d7988189a0 | ||
|
|
ff5d0cedfa | ||
|
|
f82adeba42 | ||
|
|
cc99ad59ab | ||
|
|
b66c756741 | ||
|
|
fbbdb4e131 | ||
|
|
0bf6bf7b5f | ||
|
|
865a609203 | ||
|
|
9f213cf499 | ||
|
|
1330c77ed8 | ||
|
|
2356726417 | ||
|
|
03c09917da | ||
|
|
70830cf2ca | ||
|
|
43140005f2 | ||
|
|
59e2a16a39 | ||
|
|
11d6ddf3fa | ||
|
|
b10b42eede | ||
|
|
5801b8ea56 | ||
|
|
b9461d3259 | ||
|
|
7960144be6 | ||
|
|
0f95538f39 | ||
|
|
fec512175b | ||
|
|
a427fcbf4e | ||
|
|
c49cd62b2a | ||
|
|
abf28f335c | ||
|
|
540e6d1dbc | ||
|
|
76e1128e93 | ||
|
|
cbf681ccfc | ||
|
|
30f17b4791 | ||
|
|
cd6aaaf165 | ||
|
|
289dcd660e | ||
|
|
b07428f894 | ||
|
|
dbd1d422c6 | ||
|
|
0b83e86c5e | ||
|
|
b396ce457d | ||
|
|
734e15c94d | ||
|
|
edf84248ab | ||
|
|
83dfdb9219 | ||
|
|
70b9c2981e | ||
|
|
971fcbd34c | ||
|
|
cebed0a60d | ||
|
|
8817da309f | ||
|
|
27cc0e8d00 | ||
|
|
cecd3088be | ||
|
|
412ea369f1 | ||
|
|
22ca3a2a46 | ||
|
|
92feea8a10 | ||
|
|
3af1af872e | ||
|
|
1f00925cd8 | ||
|
|
50079e2b7a | ||
|
|
02ec76980c | ||
|
|
52ad90f77e | ||
|
|
563c6e71f7 | ||
|
|
a357d77b00 | ||
|
|
abc82b0f09 | ||
|
|
3e6541deec | ||
|
|
33a972001e | ||
|
|
fe67ce0365 | ||
|
|
511944c21c |
@@ -21,3 +21,5 @@ When adding new user-facing strings:
|
|||||||
- `troubleshooter_ble_result_failure_title` (status/error title)
|
- `troubleshooter_ble_result_failure_title` (status/error title)
|
||||||
|
|
||||||
Common prefixes currently in use: `device_`, `settings_`, `support_`, `profiles_`, `press_`, `general_`, `pods_`, `upgrade_`, `widget_`, `debug_`, `permission_`, `troubleshooter_`, `overview_`, `anc_`, `onboarding_`. There is no `error_*` prefix — error labels live under the relevant feature (e.g. `general_error_label`, `troubleshooter_*_failure_*`).
|
Common prefixes currently in use: `device_`, `settings_`, `support_`, `profiles_`, `press_`, `general_`, `pods_`, `upgrade_`, `widget_`, `debug_`, `permission_`, `troubleshooter_`, `overview_`, `anc_`, `onboarding_`. There is no `error_*` prefix — error labels live under the relevant feature (e.g. `general_error_label`, `troubleshooter_*_failure_*`).
|
||||||
|
|
||||||
|
String context, character limits and file context are managed on Crowdin through the android-translation plugin's `crowdin-annotate` skill. XML comments in `values/strings.xml` no longer reach translators once a string's context has been written on Crowdin; change it there.
|
||||||
|
|||||||
@@ -32,13 +32,15 @@ ScreenshotContent.kt (mock data + composables)
|
|||||||
|------|---------|
|
|------|---------|
|
||||||
| `app/src/debug/java/.../screenshots/ScreenshotContent.kt` | Mock data composables (7 exist; `HomescreenWidgetContent` has an IDE preview only and is **not** in the Play Store pipeline) |
|
| `app/src/debug/java/.../screenshots/ScreenshotContent.kt` | Mock data composables (7 exist; `HomescreenWidgetContent` has an IDE preview only and is **not** in the Play Store pipeline) |
|
||||||
| `app/src/screenshotTest/kotlin/.../screenshots/PlayStoreScreenshots.kt` | `@PreviewTest` functions (currently: `DashboardLight`, `DashboardDark`, `CasePopUp`, `DeviceProfiles`, `AddProfile`, `DeviceSettingsReactions`, `WidgetConfiguration`) |
|
| `app/src/screenshotTest/kotlin/.../screenshots/PlayStoreScreenshots.kt` | `@PreviewTest` functions (currently: `DashboardLight`, `DashboardDark`, `CasePopUp`, `DeviceProfiles`, `AddProfile`, `DeviceSettingsReactions`, `WidgetConfiguration`) |
|
||||||
| `app/src/screenshotTest/kotlin/.../screenshots/PlayStoreLocales.kt` | Multi-preview annotations (auto-generated by batch script) |
|
| `app/src/screenshotTest/kotlin/.../screenshots/PlayStoreLocales.kt` | Multi-preview annotations. The committed content is an en-US placeholder, not meaningful data — `generate_screenshots.sh` rewrites it per batch and restores it from a `.bak` on exit. A run killed hard leaves that `.bak` behind, so the script now refuses to start until it is restored by hand |
|
||||||
| `fastlane/generate_screenshots.sh` | Batched generation; locale list (`ALL_LOCALES`) and `BATCH_SIZE` are defined inside the script |
|
| `fastlane/generate_screenshots.sh` | Batched generation; locale list (`ALL_LOCALES`) and `BATCH_SIZE` are defined inside the script |
|
||||||
| `fastlane/copy_screenshots.sh` | Copies rendered PNGs into fastlane structure |
|
| `fastlane/copy_screenshots.sh` | Copies rendered PNGs into fastlane structure |
|
||||||
|
|
||||||
## Commit policy
|
## Commit policy
|
||||||
|
|
||||||
Only the 6 smoke locales (en-US, de-DE, ja-JP, ar, zh-CN, pt-BR) have `phoneScreenshots/*.png` checked into the repo. Non-smoke locales are excluded by `.gitignore`. This mirrors permission-pilot and keeps repo size small (~7 MB vs ~67 MB for the full 68 locales).
|
Only `en-US` has `phoneScreenshots/*.png` checked into the repo — 7 PNGs, ~1 MB tracked. Every other locale is excluded by `.gitignore`.
|
||||||
|
|
||||||
|
`--smoke` still *renders* 6 locales (en-US, de-DE, ja-JP, ar, zh-CN, pt-BR), but only en-US is committed. The other five cover LTR, RTL and CJK layout so a render that breaks on non-Latin script fails during generation, and the resulting PNGs sit in the working tree for manual inspection. Nothing compares them against a baseline, so this is render coverage plus eyeballing, not regression checking.
|
||||||
|
|
||||||
Play Store's `supply` only uploads what's present in `fastlane/metadata/android/<locale>/images/phoneScreenshots/`. For locales not in the upload, Play Store retains whatever was last pushed. So full localization on Play Store is maintained by an **occasional manual** full regen + `:screenshots_only` upload — not by every PR.
|
Play Store's `supply` only uploads what's present in `fastlane/metadata/android/<locale>/images/phoneScreenshots/`. For locales not in the upload, Play Store retains whatever was last pushed. So full localization on Play Store is maintained by an **occasional manual** full regen + `:screenshots_only` upload — not by every PR.
|
||||||
|
|
||||||
@@ -90,11 +92,20 @@ Periodic, manual operation — not per-PR:
|
|||||||
```bash
|
```bash
|
||||||
./fastlane/generate_screenshots.sh # full, ~30 min, 476 PNGs (68 locales x 7)
|
./fastlane/generate_screenshots.sh # full, ~30 min, 476 PNGs (68 locales x 7)
|
||||||
./fastlane/copy_screenshots.sh --clean
|
./fastlane/copy_screenshots.sh --clean
|
||||||
bundle exec fastlane screenshots_only # uploads all 68 locales to Play Store
|
git add fastlane/metadata/android/en-US/images/phoneScreenshots/
|
||||||
git checkout -- fastlane/metadata/android/ # discard non-smoke changes (gitignored anyway)
|
if bundle exec fastlane screenshots_only; then
|
||||||
|
git checkout -- fastlane/metadata/android/ &&
|
||||||
|
git commit --only -m "chore(screenshots): Refresh Play Store screenshots" -- \
|
||||||
|
fastlane/metadata/android/en-US/images/phoneScreenshots/
|
||||||
|
else
|
||||||
|
git checkout -- fastlane/metadata/android/
|
||||||
|
echo "Upload failed; the refreshed en-US screenshots remain staged for retry."
|
||||||
|
fi
|
||||||
```
|
```
|
||||||
|
|
||||||
The `.gitignore` rule keeps non-smoke output unstaged automatically, so only the smoke locales' refreshed PNGs would show up as modifications and can be committed.
|
The `git add` has to happen before the upload. The final `git checkout` restores every tracked file under that path **from the index**, so staging the refreshed English set is precisely what makes it survive the checkout — skip the `git add` and the checkout silently reverts the refresh while the store still receives the new images.
|
||||||
|
|
||||||
|
Restoring is the checkout's job otherwise: `screenshots_only` runs `remove_unsupported_languages.sh`, which deletes 9 tracked locale directories (es-AR, sc-IT, sq-AL, uz, kmr-TR, ur-IN, zu, si-LK, nb) from the working tree before uploading — 35 tracked files, a subset of the 309 tracked non-screenshot metadata files under that path, all of them put back by the checkout. It does **not** touch the regenerated non-English PNGs: those are untracked and ignored, so they stay on disk and never show up in `git status`. Because the checkout discards any uncommitted metadata text edits too, run this refresh only with an otherwise-clean metadata tree. The final commit is path-limited on purpose, so an unrelated staged change can't ride along, and it is gated on `screenshots_only` succeeding rather than merely sequenced after it: if the upload fails, the refreshed English files stay staged for a retry instead of being committed as though they were deployed. The deleted locale directories are restored on either path.
|
||||||
|
|
||||||
## Technical Notes
|
## Technical Notes
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,7 @@
|
|||||||
"debugbadger@claude-code-cafe": true,
|
"debugbadger@claude-code-cafe": true,
|
||||||
"jvm-tools@claude-code-cafe": true,
|
"jvm-tools@claude-code-cafe": true,
|
||||||
"frontend-design@claude-plugins-official": true,
|
"frontend-design@claude-plugins-official": true,
|
||||||
"kotlin-lsp@claude-plugins-official": true,
|
"support@claude-code-cafe": true,
|
||||||
"support-investigator@claude-code-cafe": true,
|
|
||||||
"google-play@claude-code-cafe": true,
|
"google-play@claude-code-cafe": true,
|
||||||
"devtools@claude-code-cafe": true
|
"devtools@claude-code-cafe": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,4 +23,4 @@ jobs:
|
|||||||
thumbnail:
|
thumbnail:
|
||||||
permissions:
|
permissions:
|
||||||
issues: write
|
issues: write
|
||||||
uses: d4rken-org/.github/.github/workflows/thumbnail-images.yml@3756372c3c844e4817c03d27983691f9991a19f4
|
uses: d4rken-org/.github/.github/workflows/thumbnail-images.yml@94e36d9a67a887e24338f95fd0429925cea21c98
|
||||||
|
|||||||
+1
-6
@@ -17,16 +17,11 @@
|
|||||||
.kotlin
|
.kotlin
|
||||||
# Screenshot test reference images (ephemeral, regenerated on demand)
|
# Screenshot test reference images (ephemeral, regenerated on demand)
|
||||||
app/src/screenshotTest*/reference/
|
app/src/screenshotTest*/reference/
|
||||||
# Play Store phone screenshots: commit only the 6 smoke locales (mirrors permission-pilot).
|
# Play Store phone screenshots: commit only en-US.
|
||||||
# Full localization is uploaded by occasional manual regen + screenshots_only;
|
# Full localization is uploaded by occasional manual regen + screenshots_only;
|
||||||
# Play Store retains previously-uploaded screenshots for locales not pushed.
|
# Play Store retains previously-uploaded screenshots for locales not pushed.
|
||||||
fastlane/metadata/android/*/images/phoneScreenshots/*.png
|
fastlane/metadata/android/*/images/phoneScreenshots/*.png
|
||||||
!fastlane/metadata/android/en-US/images/phoneScreenshots/*.png
|
!fastlane/metadata/android/en-US/images/phoneScreenshots/*.png
|
||||||
!fastlane/metadata/android/de-DE/images/phoneScreenshots/*.png
|
|
||||||
!fastlane/metadata/android/ja-JP/images/phoneScreenshots/*.png
|
|
||||||
!fastlane/metadata/android/ar/images/phoneScreenshots/*.png
|
|
||||||
!fastlane/metadata/android/zh-CN/images/phoneScreenshots/*.png
|
|
||||||
!fastlane/metadata/android/pt-BR/images/phoneScreenshots/*.png
|
|
||||||
.codex
|
.codex
|
||||||
protocol-research/
|
protocol-research/
|
||||||
_site/
|
_site/
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ dependencies {
|
|||||||
|
|
||||||
addCompose()
|
addCompose()
|
||||||
addGlance()
|
addGlance()
|
||||||
|
addWorkerManager()
|
||||||
addDataStore()
|
addDataStore()
|
||||||
addNavigation3()
|
addNavigation3()
|
||||||
addSerialization()
|
addSerialization()
|
||||||
|
|||||||
@@ -47,6 +47,13 @@ internal enum class FossUpgradeView {
|
|||||||
STATUS_UPGRADED,
|
STATUS_UPGRADED,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The Settings row and the PITCH title both read this one resource, so they cannot name the tier
|
||||||
|
// differently — unlike the composed brand title, this stays a support ask ("Sponsor CAPod") rather
|
||||||
|
// than naming the flavor. gplay's counterpart in UpgradeScreen.kt composes from brandTitleText
|
||||||
|
// instead; each flavor implementation lives only in its own source set.
|
||||||
|
@Composable
|
||||||
|
internal fun settingsUpgradeStatusTitle(): String = stringResource(R.string.upgrade_foss_sponsor_label)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UpgradeScreenHost(
|
fun UpgradeScreenHost(
|
||||||
route: Nav.Main.Upgrade = Nav.Main.Upgrade(),
|
route: Nav.Main.Upgrade = Nav.Main.Upgrade(),
|
||||||
@@ -115,7 +122,7 @@ internal fun UpgradeScreen(
|
|||||||
// Status views describe the existing install, not a support ask — they get the composed
|
// Status views describe the existing install, not a support ask — they get the composed
|
||||||
// flavor title, with the postfix highlighted for supporters like the dashboard does it.
|
// flavor title, with the postfix highlighted for supporters like the dashboard does it.
|
||||||
title = if (view == FossUpgradeView.PITCH) {
|
title = if (view == FossUpgradeView.PITCH) {
|
||||||
AnnotatedString(stringResource(R.string.settings_upgrade_status_label))
|
AnnotatedString(settingsUpgradeStatusTitle())
|
||||||
} else {
|
} else {
|
||||||
// "CAPod FOSS", not "CAPod Pro": the FOSS flavor's own qualifier resource supplies the
|
// "CAPod FOSS", not "CAPod Pro": the FOSS flavor's own qualifier resource supplies the
|
||||||
// tier word, so the title names this build. The upgraded gate keeps the highlight for
|
// tier word, so the title names this build. The upgraded gate keeps the highlight for
|
||||||
|
|||||||
@@ -42,8 +42,10 @@ class UpgradeViewModel @Inject constructor(
|
|||||||
|
|
||||||
// Which presentation the screen shows. The manage route (settings "upgrade status" entry)
|
// Which presentation the screen shows. The manage route (settings "upgrade status" entry)
|
||||||
// gets a status view first; the pitch only appears once a free user asks for the upgrade
|
// gets a status view first; the pitch only appears once a free user asks for the upgrade
|
||||||
// options. Upgrading wins over that choice — completing the sponsor flow from the pitch must
|
// options. Upgrading wins on EVERY route, not just manage: forced routes (Pro-locked settings)
|
||||||
// land on the upgraded status, not back on the ask. null until the route is bound.
|
// stay open after the sponsor flow completes, and the pitch with its live sponsor button reads
|
||||||
|
// as "sponsoring didn't work" to a fresh supporter — the toast alone is too transient for a
|
||||||
|
// money moment without a receipt behind it. null until the route is bound.
|
||||||
internal val state: StateFlow<State?> = combine(
|
internal val state: StateFlow<State?> = combine(
|
||||||
routeFlow,
|
routeFlow,
|
||||||
upgradeRepo.upgradeInfo,
|
upgradeRepo.upgradeInfo,
|
||||||
@@ -51,7 +53,7 @@ class UpgradeViewModel @Inject constructor(
|
|||||||
) { route, info, showOptions ->
|
) { route, info, showOptions ->
|
||||||
val view = when {
|
val view = when {
|
||||||
route == null -> null
|
route == null -> null
|
||||||
route.manage && info.isPro -> FossUpgradeView.STATUS_UPGRADED
|
info.isPro -> FossUpgradeView.STATUS_UPGRADED
|
||||||
route.manage && !showOptions -> FossUpgradeView.STATUS_FREE
|
route.manage && !showOptions -> FossUpgradeView.STATUS_FREE
|
||||||
else -> FossUpgradeView.PITCH
|
else -> FossUpgradeView.PITCH
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Skenk</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Ek het reeds geskenk</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Ek spandeer al my geld op AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS is gratis en oopbron. As u dit nuttig vind, oorweeg dit om ontwikkeling te befonds om die projek aan die gang te hou.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS is gratis en oopbron. As u dit nuttig vind, oorweeg dit om ontwikkeling te befonds om die projek aan die gang te hou.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Borg ontwikkeling</string>
|
<string name="upgrade_foss_sponsor_action">Borg ontwikkeling</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Geen advertensies. Geen opsporing. Geen Google Play-binding.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Geen advertensies. Geen opsporing. Geen Google Play-binding.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Ondersteuner sedert %s</string>
|
<string name="upgrade_foss_supporter_since">Ondersteuner sedert %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Dankie dat jy CAPod se ontwikkeling ondersteun!</string>
|
<string name="upgrade_foss_supporter_thanks">Dankie dat jy CAPod se ontwikkeling ondersteun!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Maak borgblad oop</string>
|
<string name="upgrade_foss_sponsor_again_action">Maak borgblad oop</string>
|
||||||
<string name="settings_upgrade_status_label">Ondersteun CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Ondersteun CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Jou ondersteunersstatus.</string>
|
<string name="settings_upgrade_status_description">Jou ondersteunersstatus.</string>
|
||||||
<string name="upgrade_screen_why_title">Opgraderingsvoordele</string>
|
<string name="upgrade_screen_why_title">Opgraderingsvoordele</string>
|
||||||
<string name="upgrade_screen_how_title">Hoe om te help</string>
|
<string name="upgrade_screen_how_title">Hoe om te help</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">ልገሳ</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">አስቀድሜ ልገሳ ፈጽሜአለሁ</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">ገንዘቤን በሙሉ በAirPods ላይ አውጥቻለሁ</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS ነፃ እና ክፍት ምንጭ ነው። ግኾሚ ሆኖ ካግኝት፣ ፕሮጀክቱ ቀጥሎ እንደይይድ ለመርዳት ላማቱን ማስደገፏ ያስቡ።</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS ነፃ እና ክፍት ምንጭ ነው። ግኾሚ ሆኖ ካግኝት፣ ፕሮጀክቱ ቀጥሎ እንደይይድ ለመርዳት ላማቱን ማስደገፏ ያስቡ።</string>
|
||||||
<string name="upgrade_foss_sponsor_action">ልማትን ይደግፉ</string>
|
<string name="upgrade_foss_sponsor_action">ልማትን ይደግፉ</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">ምንም ማስታወቂያ የሉም። ምንም ክትትል የሉም። ምንም Google Play ቆለፋ የሉም።</string>
|
<string name="upgrade_foss_sponsor_subtitle">ምንም ማስታወቂያ የሉም። ምንም ክትትል የሉም። ምንም Google Play ቆለፋ የሉም።</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">ደጋፊ ከ%s ጀምሮ</string>
|
<string name="upgrade_foss_supporter_since">ደጋፊ ከ%s ጀምሮ</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">የCAPod ልማትን ስለደገፉ እናመሰግናለን!</string>
|
<string name="upgrade_foss_supporter_thanks">የCAPod ልማትን ስለደገፉ እናመሰግናለን!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">የስፖንሰር ገጽን ክፈት</string>
|
<string name="upgrade_foss_sponsor_again_action">የስፖንሰር ገጽን ክፈት</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod ን ደግፍ</string>
|
<string name="upgrade_foss_sponsor_label">CAPod ን ደግፍ</string>
|
||||||
<string name="settings_upgrade_status_description">የእርስዎ ደጋፊ ሁኔታ።</string>
|
<string name="settings_upgrade_status_description">የእርስዎ ደጋፊ ሁኔታ።</string>
|
||||||
<string name="upgrade_screen_why_title">የማሻሻል ጥቅማጥቅሞች</string>
|
<string name="upgrade_screen_why_title">የማሻሻል ጥቅማጥቅሞች</string>
|
||||||
<string name="upgrade_screen_how_title">እንዴት መርዳት እንደሚችሉ</string>
|
<string name="upgrade_screen_how_title">እንዴት መርዳት እንደሚችሉ</string>
|
||||||
|
|||||||
@@ -1,24 +1,21 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">تبرع</string>
|
<string name="upgrade_foss_preamble">برنامج كابود FOSS مجّاني ومفتوح المصدر. إذا وجدته مفيدًا، ففكّر في دعم تطويره للمساعدة في استمرار المشروع.</string>
|
||||||
<string name="foss_upgrade_alreadydonated_label">لقد تبرعت بالفعل</string>
|
<string name="upgrade_foss_sponsor_action">ادعم التطوير</string>
|
||||||
<string name="foss_upgrade_no_money_label">أنفق كل أموالي على سماعات أيربودز</string>
|
<string name="upgrade_foss_sponsor_subtitle">لا إعلانات. لا تتبّع. لا قيود من جوجل بلاي.</string>
|
||||||
<string name="upgrade_foss_preamble">برنامج كابود FOSS مجاني ومفتوح المصدر. إذا وجدته مفيدًا، ففكر في دعم تطويره للمساعدة في استمرار المشروع.</string>
|
|
||||||
<string name="upgrade_foss_sponsor_action">دعم التطوير</string>
|
|
||||||
<string name="upgrade_foss_sponsor_subtitle">لا إعلانات. لا تتبع. لا قيود من جوجل بلاي.</string>
|
|
||||||
<string name="upgrade_foss_sponsor_returned_early">هل عدت بالفعل؟ دعمك يبقي كابود حيًّا.</string>
|
<string name="upgrade_foss_sponsor_returned_early">هل عدت بالفعل؟ دعمك يبقي كابود حيًّا.</string>
|
||||||
<string name="upgrade_foss_supporter_since">داعم منذ %s</string>
|
<string name="upgrade_foss_supporter_since">داعمٌ منذ %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">شكرًا لدعمك تطوير CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">شكرًا لدعمك تطوير كابود!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">فتح صفحة الرعاية</string>
|
<string name="upgrade_foss_sponsor_again_action">افتح صفحة الرعاية</string>
|
||||||
<string name="settings_upgrade_status_label">دعم كابود</string>
|
<string name="upgrade_foss_sponsor_label">دعم كابود</string>
|
||||||
<string name="settings_upgrade_status_description">حالة دعمك.</string>
|
<string name="settings_upgrade_status_description">حالة دعمك.</string>
|
||||||
<string name="upgrade_screen_why_title">مزايا الترقية</string>
|
<string name="upgrade_screen_why_title">مزايا الترقية</string>
|
||||||
<string name="upgrade_screen_how_title">كيفية المساعدة</string>
|
<string name="upgrade_screen_how_title">كيفية المساعدة</string>
|
||||||
<string name="upgrade_screen_how_body">كُن راعيًا وساهم في تطوير المشروع! اضغط على الزرّ أدناه لتفعيل جميع الميزات الإضافية وفتح ملفّي الشخصي على GitHub Sponsors.</string>
|
<string name="upgrade_screen_how_body">كُن راعيًا وادعم تطوير المشروع! اضغط على الزرّ أدناه لتفعيل جميع المزايا الإضافية وفتح ملفّي الشخصي على GitHub Sponsors.</string>
|
||||||
<string name="upgrade_screen_status_free_title">النسخة المجّانية</string>
|
<string name="upgrade_screen_status_free_title">النسخة المجّانية</string>
|
||||||
<string name="upgrade_screen_status_free_body">أنت تستخدم النسخة المجّانية من كابود. يمكنك فتح ميزات إضافية من خلال دعم التطوير.</string>
|
<string name="upgrade_screen_status_free_body">أنت تستخدم النسخة المجّانية من كابود. يمكنك فتح مزايا إضافيةٍ عبر دعم التطوير.</string>
|
||||||
<string name="upgrade_screen_status_free_action">الاطّلاع على خيارات الترقية</string>
|
<string name="upgrade_screen_status_free_action">اطّلع على خيارات الترقية</string>
|
||||||
<string name="upgrade_screen_status_upgraded_title">الترقية نشطة</string>
|
<string name="upgrade_screen_status_upgraded_title">الترقية نشيطة</string>
|
||||||
<string name="upgrade_screen_recurring_title">أبقِ التطبيق مستمرًّا</string>
|
<string name="upgrade_screen_recurring_title">أبقِ التطبيق مستمرًّا</string>
|
||||||
<string name="upgrade_screen_recurring_body">يستمرّ كابود في التطوّر من خلال التحديثات والإصلاحات. إذا كنت ترغب في دعم هذا التطوّر، ففكّر في التبرّع بشكل دوري عبر GitHub Sponsors.</string>
|
<string name="upgrade_screen_recurring_body">يستمرّ كابود في التطوّر عبر التحديثات والإصلاحات. إذا كنت ترغب في دعم هذا التطوّر، ففكّر في التبرّع بشكلٍ دوريٍّ عبر GitHub Sponsors.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">İanə ver</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Artıq ianə vermişəm</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Bütün pulumu AirPods-lara xərcləyirəm</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS pulsuzdur və açıq mənbəlidir. Faydalı tapırsınızsa, layihənin davamına kömək etmək üçün inkişafı maliyyələşdirməyi düşünün.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS pulsuzdur və açıq mənbəlidir. Faydalı tapırsınızsa, layihənin davamına kömək etmək üçün inkişafı maliyyələşdirməyi düşünün.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">İnkişafı sponsor edin</string>
|
<string name="upgrade_foss_sponsor_action">İnkişafı sponsor edin</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Reklam yoxdur. İzləmə yoxdur. Google Play bağlılığı yoxdur.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Reklam yoxdur. İzləmə yoxdur. Google Play bağlılığı yoxdur.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">%s tarixindən bəri dəstəkçi</string>
|
<string name="upgrade_foss_supporter_since">%s tarixindən bəri dəstəkçi</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">CAPod-un inkişafını dəstəklədiyiniz üçün təşəkkürlər!</string>
|
<string name="upgrade_foss_supporter_thanks">CAPod-un inkişafını dəstəklədiyiniz üçün təşəkkürlər!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Sponsor səhifəsini aç</string>
|
<string name="upgrade_foss_sponsor_again_action">Sponsor səhifəsini aç</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod-u sponsorlaşdırın</string>
|
<string name="upgrade_foss_sponsor_label">CAPod-u sponsorlaşdırın</string>
|
||||||
<string name="settings_upgrade_status_description">Sizin tərəfdar statusu.</string>
|
<string name="settings_upgrade_status_description">Sizin tərəfdar statusu.</string>
|
||||||
<string name="upgrade_screen_why_title">Yüksəltmə üstünləri</string>
|
<string name="upgrade_screen_why_title">Yüksəltmə üstünləri</string>
|
||||||
<string name="upgrade_screen_how_title">Necə kömək etmək</string>
|
<string name="upgrade_screen_how_title">Necə kömək etmək</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Ахвяраваць</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Я ўжо ахвяраваў</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Я патраціў усе грошы на AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS бясплатны і з адкрытым зыходным кодам. Калі вы лічыце яго карысным, разгледзьце магчымасць спансіравання распрацоўкі, каб дапамагчы трымаць праект ў жывых.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS бясплатны і з адкрытым зыходным кодам. Калі вы лічыце яго карысным, разгледзьце магчымасць спансіравання распрацоўкі, каб дапамагчы трымаць праект ў жывых.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Падтрымаць распрацоўку</string>
|
<string name="upgrade_foss_sponsor_action">Падтрымаць распрацоўку</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Ніякай рэкламы. Ніякай адсочкі. Ніякай залежнасці ад Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Ніякай рэкламы. Ніякай адсочкі. Ніякай залежнасці ад Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Спонсар з %s</string>
|
<string name="upgrade_foss_supporter_since">Спонсар з %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Дзякуй за падтрымку развіцця CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Дзякуй за падтрымку развіцця CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Адкрыць старонку спонсарства</string>
|
<string name="upgrade_foss_sponsor_again_action">Адкрыць старонку спонсарства</string>
|
||||||
<string name="settings_upgrade_status_label">Спонсараваць CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Спонсараваць CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Ваш статус прыхільніка.</string>
|
<string name="settings_upgrade_status_description">Ваш статус прыхільніка.</string>
|
||||||
<string name="upgrade_screen_why_title">Перавагі абнаўлення</string>
|
<string name="upgrade_screen_why_title">Перавагі абнаўлення</string>
|
||||||
<string name="upgrade_screen_how_title">Як дапамагчы</string>
|
<string name="upgrade_screen_how_title">Як дапамагчы</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Дарение</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Вече съм дарил</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Харча всичките си пари за AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS е безплатен и с отворен код. Ако ви е полезен, размислете да подкрепите разработката, за да помогнете проектът да продължи.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS е безплатен и с отворен код. Ако ви е полезен, размислете да подкрепите разработката, за да помогнете проектът да продължи.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Спонсорирайте разработката</string>
|
<string name="upgrade_foss_sponsor_action">Спонсорирайте разработката</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Без реклами. Без следене. Без заключване в Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Без реклами. Без следене. Без заключване в Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Поддържник от %s</string>
|
<string name="upgrade_foss_supporter_since">Поддържник от %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Благодарим ви, че подкрепяте развитието на CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Благодарим ви, че подкрепяте развитието на CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Отвори страницата за спонсорство</string>
|
<string name="upgrade_foss_sponsor_again_action">Отвори страницата за спонсорство</string>
|
||||||
<string name="settings_upgrade_status_label">Спонсорирайте CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Спонсорирайте CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Вашият статус на поддръжник.</string>
|
<string name="settings_upgrade_status_description">Вашият статус на поддръжник.</string>
|
||||||
<string name="upgrade_screen_why_title">Преимущества на надстройката</string>
|
<string name="upgrade_screen_why_title">Преимущества на надстройката</string>
|
||||||
<string name="upgrade_screen_how_title">Как да помогнете</string>
|
<string name="upgrade_screen_how_title">Как да помогнете</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">দান করুন</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">আমি ইতিমধ্যে দান করেছি</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">আমি আমার সব টাকা AirPods এর জন্য খরচ করি</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS বিনামূল্যে এবং মুক্ত উৎস। আপনি যদি এটি উপযোগী মনে করেন, প্রকল্পটি চালু রাখতে সাহায্য করতে ডেভেলপমেন্ট স্পনসর করার কথা বিবেচনা করুন।</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS বিনামূল্যে এবং মুক্ত উৎস। আপনি যদি এটি উপযোগী মনে করেন, প্রকল্পটি চালু রাখতে সাহায্য করতে ডেভেলপমেন্ট স্পনসর করার কথা বিবেচনা করুন।</string>
|
||||||
<string name="upgrade_foss_sponsor_action">স্পনসর ডেভলপমেন্ট</string>
|
<string name="upgrade_foss_sponsor_action">স্পনসর ডেভলপমেন্ট</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">কোনো বিজ্ঞাপন নেই। কোনো ট্র্যাকিং নেই। Google Play-এর সাথে বাঁধানো নেই।</string>
|
<string name="upgrade_foss_sponsor_subtitle">কোনো বিজ্ঞাপন নেই। কোনো ট্র্যাকিং নেই। Google Play-এর সাথে বাঁধানো নেই।</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">%s থেকে সমর্থক</string>
|
<string name="upgrade_foss_supporter_since">%s থেকে সমর্থক</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">CAPod-এর উন্নয়নে সমর্থন করার জন্য আপনাকে ধন্যবাদ!</string>
|
<string name="upgrade_foss_supporter_thanks">CAPod-এর উন্নয়নে সমর্থন করার জন্য আপনাকে ধন্যবাদ!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">স্পনসর পৃষ্ঠা খুলুন</string>
|
<string name="upgrade_foss_sponsor_again_action">স্পনসর পৃষ্ঠা খুলুন</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod-কে স্পন্সর করুন</string>
|
<string name="upgrade_foss_sponsor_label">CAPod-কে স্পন্সর করুন</string>
|
||||||
<string name="settings_upgrade_status_description">আপনার সমর্থক স্থিতি।</string>
|
<string name="settings_upgrade_status_description">আপনার সমর্থক স্থিতি।</string>
|
||||||
<string name="upgrade_screen_why_title">আপগ্রেড সুবিধা</string>
|
<string name="upgrade_screen_why_title">আপগ্রেড সুবিধা</string>
|
||||||
<string name="upgrade_screen_how_title">কিভাবে সাহায্য করতে পারি</string>
|
<string name="upgrade_screen_how_title">কিভাবে সাহায্য করতে পারি</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Donacions</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Ja he donat</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Gasto tots els meus diners en AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">El CAPod FOSS és gratuït i de codi obert. Si el trobeu útil, considereu patrocinar el desenvolupament per ajudar a mantenir el projecte en marxa.</string>
|
<string name="upgrade_foss_preamble">El CAPod FOSS és gratuït i de codi obert. Si el trobeu útil, considereu patrocinar el desenvolupament per ajudar a mantenir el projecte en marxa.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Patrocina el desenvolupament</string>
|
<string name="upgrade_foss_sponsor_action">Patrocina el desenvolupament</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Sense anuncis. Sense seguiment. Sense dependència del Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Sense anuncis. Sense seguiment. Sense dependència del Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Col·laborador des de %s</string>
|
<string name="upgrade_foss_supporter_since">Col·laborador des de %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Gràcies per donar suport al desenvolupament del CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Gràcies per donar suport al desenvolupament del CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Obre la pàgina del patrocinador</string>
|
<string name="upgrade_foss_sponsor_again_action">Obre la pàgina del patrocinador</string>
|
||||||
<string name="settings_upgrade_status_label">Patrocineu el CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Patrocineu el CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">El vostre estat de col·laborador.</string>
|
<string name="settings_upgrade_status_description">El vostre estat de col·laborador.</string>
|
||||||
<string name="upgrade_screen_why_title">Beneficis de la millora</string>
|
<string name="upgrade_screen_why_title">Beneficis de la millora</string>
|
||||||
<string name="upgrade_screen_how_title">Com ajudar</string>
|
<string name="upgrade_screen_how_title">Com ajudar</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Přispět</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Již jsem přispěl/a</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Všechny peníze jsem utratil/a za AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">Aplikace CAPod FOSS je zdarma a open source. Pokud vám přijde užitečná, zvažte sponzorování vývoje, abyste pomohli udržet projekt v chodu.</string>
|
<string name="upgrade_foss_preamble">Aplikace CAPod FOSS je zdarma a open source. Pokud vám přijde užitečná, zvažte sponzorování vývoje, abyste pomohli udržet projekt v chodu.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Sponzorovat vývoj</string>
|
<string name="upgrade_foss_sponsor_action">Sponzorovat vývoj</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Žádné reklamy. Žádné sledování. Žádná závislost na Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Žádné reklamy. Žádné sledování. Žádná závislost na Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Podporovatel od %s</string>
|
<string name="upgrade_foss_supporter_since">Podporovatel od %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Děkujeme za podporu vývoje CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Děkujeme za podporu vývoje CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Otevřít stránku sponzora</string>
|
<string name="upgrade_foss_sponsor_again_action">Otevřít stránku sponzora</string>
|
||||||
<string name="settings_upgrade_status_label">Sponzorovat CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Sponzorovat CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Váš stav podporovatele.</string>
|
<string name="settings_upgrade_status_description">Váš stav podporovatele.</string>
|
||||||
<string name="upgrade_screen_why_title">Výhody upgradu</string>
|
<string name="upgrade_screen_why_title">Výhody upgradu</string>
|
||||||
<string name="upgrade_screen_how_title">Jak pomoci</string>
|
<string name="upgrade_screen_how_title">Jak pomoci</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Doner</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Jeg har allerede doneret</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Jeg bruger alle mine penge på AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS er gratis og open source. Hvis du finder det nüttigt, kan du overveje at sponsorere udviklingen for at hjælpe projektet med at fortsætte.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS er gratis og open source. Hvis du finder det nüttigt, kan du overveje at sponsorere udviklingen for at hjælpe projektet med at fortsætte.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Sponsorudvikling</string>
|
<string name="upgrade_foss_sponsor_action">Sponsorudvikling</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Ingen annoncer. Ingen sporing. Ingen Google Play-lås.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Ingen annoncer. Ingen sporing. Ingen Google Play-lås.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Støtte siden %s</string>
|
<string name="upgrade_foss_supporter_since">Støtte siden %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Tak fordi du støtter udviklingen af CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Tak fordi du støtter udviklingen af CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Åbn sponsorside</string>
|
<string name="upgrade_foss_sponsor_again_action">Åbn sponsorside</string>
|
||||||
<string name="settings_upgrade_status_label">Sponsor CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Sponsor CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Din supporterstatus.</string>
|
<string name="settings_upgrade_status_description">Din supporterstatus.</string>
|
||||||
<string name="upgrade_screen_why_title">Opgraderingens fordele</string>
|
<string name="upgrade_screen_why_title">Opgraderingens fordele</string>
|
||||||
<string name="upgrade_screen_how_title">Sådan hjælper du</string>
|
<string name="upgrade_screen_how_title">Sådan hjælper du</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Spenden</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Ich habe schon gespendet</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Hab alles für AirPods ausgegeben</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS ist kostenlos und Open Source. Wenn du es nützlich findest, erwäge, die Entwicklung zu sponsern, um das Projekt am Laufen zu halten.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS ist kostenlos und Open Source. Wenn du es nützlich findest, erwäge, die Entwicklung zu sponsern, um das Projekt am Laufen zu halten.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Fördere Entwicklung</string>
|
<string name="upgrade_foss_sponsor_action">Fördere Entwicklung</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Keine Werbung. Kein Tracking. Keine Google-Play-Bindung.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Keine Werbung. Kein Tracking. Keine Google-Play-Bindung.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Unterstützer seit %s</string>
|
<string name="upgrade_foss_supporter_since">Unterstützer seit %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Vielen Dank, dass du die Entwicklung von CAPod unterstützt!</string>
|
<string name="upgrade_foss_supporter_thanks">Vielen Dank, dass du die Entwicklung von CAPod unterstützt!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Sponsoring-Seite öffnen</string>
|
<string name="upgrade_foss_sponsor_again_action">Sponsoring-Seite öffnen</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod unterstützen</string>
|
<string name="upgrade_foss_sponsor_label">CAPod unterstützen</string>
|
||||||
<string name="settings_upgrade_status_description">Dein Unterstützerstatus.</string>
|
<string name="settings_upgrade_status_description">Dein Unterstützerstatus.</string>
|
||||||
<string name="upgrade_screen_why_title">Vorteile des Upgrades</string>
|
<string name="upgrade_screen_why_title">Vorteile des Upgrades</string>
|
||||||
<string name="upgrade_screen_how_title">Wie man hilft</string>
|
<string name="upgrade_screen_how_title">Wie man hilft</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Δωρεά</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Ήδη δώρισα</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Ξόδεψα όλα τα χρήματά μου στα AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">Το CAPod FOSS είναι δωρεάν και ανοιχτού κώδικα. Αν το βρίσκετε χρήσιμο, εξετάστε το ενδεχόμενο να χρηματοδοτήσετε την ανάπτυξη για να συνεχίσει το έργο.</string>
|
<string name="upgrade_foss_preamble">Το CAPod FOSS είναι δωρεάν και ανοιχτού κώδικα. Αν το βρίσκετε χρήσιμο, εξετάστε το ενδεχόμενο να χρηματοδοτήσετε την ανάπτυξη για να συνεχίσει το έργο.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Χορηγήστε την ανάπτυξη</string>
|
<string name="upgrade_foss_sponsor_action">Χορηγήστε την ανάπτυξη</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Χωρίς διαφημίσεις. Χωρίς παρακολούθηση. Χωρίς δέσμευση στο Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Χωρίς διαφημίσεις. Χωρίς παρακολούθηση. Χωρίς δέσμευση στο Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Υποστηρικτής από %s</string>
|
<string name="upgrade_foss_supporter_since">Υποστηρικτής από %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Σας ευχαριστούμε που υποστηρίζετε την ανάπτυξη του CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Σας ευχαριστούμε που υποστηρίζετε την ανάπτυξη του CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Άνοιγμα σελίδας χορηγίας</string>
|
<string name="upgrade_foss_sponsor_again_action">Άνοιγμα σελίδας χορηγίας</string>
|
||||||
<string name="settings_upgrade_status_label">Χορηγήστε το CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Χορηγήστε το CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Η κατάστασή σας ως υποστηρικτή.</string>
|
<string name="settings_upgrade_status_description">Η κατάστασή σας ως υποστηρικτή.</string>
|
||||||
<string name="upgrade_screen_why_title">Πλεονεκτήματα αναβάθμισης</string>
|
<string name="upgrade_screen_why_title">Πλεονεκτήματα αναβάθμισης</string>
|
||||||
<string name="upgrade_screen_how_title">Πώς να βοηθήσετε</string>
|
<string name="upgrade_screen_how_title">Πώς να βοηθήσετε</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Donar</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Ya doné</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Gasto todo mi dinero en AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS es gratuito y de código abierto. Si lo encontrás útil, considerá patrocinar el desarrollo para ayudar a mantener el proyecto en marcha.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS es gratuito y de código abierto. Si lo encontrás útil, considerá patrocinar el desarrollo para ayudar a mantener el proyecto en marcha.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Sponsorear el desarrollo</string>
|
<string name="upgrade_foss_sponsor_action">Sponsorear el desarrollo</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Sin publicidad. Sin rastreo. Sin dependencia de Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Sin publicidad. Sin rastreo. Sin dependencia de Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Colaborador desde %s</string>
|
<string name="upgrade_foss_supporter_since">Colaborador desde %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">¡Gracias por apoyar el desarrollo de CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">¡Gracias por apoyar el desarrollo de CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Abrir página de patrocinio</string>
|
<string name="upgrade_foss_sponsor_again_action">Abrir página de patrocinio</string>
|
||||||
<string name="settings_upgrade_status_label">Apoyá CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Apoyá CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Tu estado de patrocinador.</string>
|
<string name="settings_upgrade_status_description">Tu estado de patrocinador.</string>
|
||||||
<string name="upgrade_screen_why_title">Beneficios de la mejora</string>
|
<string name="upgrade_screen_why_title">Beneficios de la mejora</string>
|
||||||
<string name="upgrade_screen_how_title">Como ayudar</string>
|
<string name="upgrade_screen_how_title">Como ayudar</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Donar</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Ya doné</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Gasto todo mi dinero en AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS es gratuito y de código abierto. Si lo encuentras útil, considera patrocinar el desarrollo para ayudar a mantener el proyecto.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS es gratuito y de código abierto. Si lo encuentras útil, considera patrocinar el desarrollo para ayudar a mantener el proyecto.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Patrocinar el desarrollo</string>
|
<string name="upgrade_foss_sponsor_action">Patrocinar el desarrollo</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Sin anuncios. Sin rastreo. Sin dependencia de Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Sin anuncios. Sin rastreo. Sin dependencia de Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Colaborador desde %s</string>
|
<string name="upgrade_foss_supporter_since">Colaborador desde %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">¡Gracias por apoyar el desarrollo de CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">¡Gracias por apoyar el desarrollo de CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Abrir página de patrocinio</string>
|
<string name="upgrade_foss_sponsor_again_action">Abrir página de patrocinio</string>
|
||||||
<string name="settings_upgrade_status_label">Patrocina CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Patrocina CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Tu estado de patrocinador.</string>
|
<string name="settings_upgrade_status_description">Tu estado de patrocinador.</string>
|
||||||
<string name="upgrade_screen_why_title">Beneficios de la actualización</string>
|
<string name="upgrade_screen_why_title">Beneficios de la actualización</string>
|
||||||
<string name="upgrade_screen_how_title">Cómo ayudar</string>
|
<string name="upgrade_screen_how_title">Cómo ayudar</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Donar</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Ya he donado</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Gasto todo mi dinero en AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS es gratuito y de código abierto. Si lo encuentras útil, considera patrocinar el desarrollo para ayudar a mantener el proyecto en marcha.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS es gratuito y de código abierto. Si lo encuentras útil, considera patrocinar el desarrollo para ayudar a mantener el proyecto en marcha.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Patrocinadores</string>
|
<string name="upgrade_foss_sponsor_action">Patrocinadores</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Sin anuncios. Sin rastreo. Sin dependencia de Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Sin anuncios. Sin rastreo. Sin dependencia de Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Colaborador desde %s</string>
|
<string name="upgrade_foss_supporter_since">Colaborador desde %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">¡Gracias por apoyar el desarrollo de CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">¡Gracias por apoyar el desarrollo de CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Abrir página de patrocinio</string>
|
<string name="upgrade_foss_sponsor_again_action">Abrir página de patrocinio</string>
|
||||||
<string name="settings_upgrade_status_label">Patrocinar CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Patrocinar CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Tu estado como patrocinador.</string>
|
<string name="settings_upgrade_status_description">Tu estado como patrocinador.</string>
|
||||||
<string name="upgrade_screen_why_title">Beneficios de la actualización</string>
|
<string name="upgrade_screen_why_title">Beneficios de la actualización</string>
|
||||||
<string name="upgrade_screen_how_title">Como ayudar</string>
|
<string name="upgrade_screen_how_title">Como ayudar</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Anneta</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Juba annetasin</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Kulutasin kogu raha AirPodsidele</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS on tasuta ja avatud lähtekoodiga. Kui sellest on sulle kasu, kaalu arenduse rahastamist, et aidata projekti arendada.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS on tasuta ja avatud lähtekoodiga. Kui sellest on sulle kasu, kaalu arenduse rahastamist, et aidata projekti arendada.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Rahasta arendamist</string>
|
<string name="upgrade_foss_sponsor_action">Rahasta arendamist</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Reklaami pole. Jälgimist pole. Google Play lukustust pole.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Reklaami pole. Jälgimist pole. Google Play lukustust pole.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Toetaja alates %s</string>
|
<string name="upgrade_foss_supporter_since">Toetaja alates %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Täname, et toetad CAPodi arendust!</string>
|
<string name="upgrade_foss_supporter_thanks">Täname, et toetad CAPodi arendust!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Ava sponsorlehekülg</string>
|
<string name="upgrade_foss_sponsor_again_action">Ava sponsorlehekülg</string>
|
||||||
<string name="settings_upgrade_status_label">Rahasta CAPodi</string>
|
<string name="upgrade_foss_sponsor_label">Rahasta CAPodi</string>
|
||||||
<string name="settings_upgrade_status_description">Sinu toetaja staatus.</string>
|
<string name="settings_upgrade_status_description">Sinu toetaja staatus.</string>
|
||||||
<string name="upgrade_screen_why_title">Uuendamise eelised</string>
|
<string name="upgrade_screen_why_title">Uuendamise eelised</string>
|
||||||
<string name="upgrade_screen_how_title">Kuidas aidata?</string>
|
<string name="upgrade_screen_how_title">Kuidas aidata?</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Eman dohaintza</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Dagoeneko eman dut dohaintza</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Nire diru guztia AirPods-etan gastatzen dut</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS doakoa eta kode irekikoa da. Erabilgarria iruditzen bazaizu, kontuan hartu garapena babestu proiektua aurrera jarraitzeko.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS doakoa eta kode irekikoa da. Erabilgarria iruditzen bazaizu, kontuan hartu garapena babestu proiektua aurrera jarraitzeko.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Garapena babestu</string>
|
<string name="upgrade_foss_sponsor_action">Garapena babestu</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Iragarkirik ez. Jarraipenik ez. Google Play-ren lotura ez.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Iragarkirik ez. Jarraipenik ez. Google Play-ren lotura ez.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Laguntzaile %s(e)tik aurrera</string>
|
<string name="upgrade_foss_supporter_since">Laguntzaile %s(e)tik aurrera</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Eskerrik asko CAPod-en garapena babesten duzulako!</string>
|
<string name="upgrade_foss_supporter_thanks">Eskerrik asko CAPod-en garapena babesten duzulako!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Ireki babesle-orria</string>
|
<string name="upgrade_foss_sponsor_again_action">Ireki babesle-orria</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod babeslatu</string>
|
<string name="upgrade_foss_sponsor_label">CAPod babeslatu</string>
|
||||||
<string name="settings_upgrade_status_description">Zure babesle egoera</string>
|
<string name="settings_upgrade_status_description">Zure babesle egoera</string>
|
||||||
<string name="upgrade_screen_why_title">Hobekuntza-onurak</string>
|
<string name="upgrade_screen_why_title">Hobekuntza-onurak</string>
|
||||||
<string name="upgrade_screen_how_title">Nola lagundu</string>
|
<string name="upgrade_screen_how_title">Nola lagundu</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">کمک مالی</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">کمک مالی کردهام</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">من تمام پولم را خرج ایرپاد میکنم</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS رایگان و متن-باز است. اگر آن را مفید یافتید، حمایت مالی از توسعه را در نظر بگیرید تا پروژه ادامه یابد.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS رایگان و متن-باز است. اگر آن را مفید یافتید، حمایت مالی از توسعه را در نظر بگیرید تا پروژه ادامه یابد.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">حامی توسعه دهنده</string>
|
<string name="upgrade_foss_sponsor_action">حامی توسعه دهنده</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">بدون تبلیغ. بدون ردیابی. بدون وابستگی به Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">بدون تبلیغ. بدون ردیابی. بدون وابستگی به Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">حامی از %s</string>
|
<string name="upgrade_foss_supporter_since">حامی از %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">از حمایت شما از توسعه CAPod سپاسگزاریم!</string>
|
<string name="upgrade_foss_supporter_thanks">از حمایت شما از توسعه CAPod سپاسگزاریم!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">باز کردن صفحه حمایت مالی</string>
|
<string name="upgrade_foss_sponsor_again_action">باز کردن صفحه حمایت مالی</string>
|
||||||
<string name="settings_upgrade_status_label">حمایت از CAPod</string>
|
<string name="upgrade_foss_sponsor_label">حمایت از CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">وضعیت حمایتی شما.</string>
|
<string name="settings_upgrade_status_description">وضعیت حمایتی شما.</string>
|
||||||
<string name="upgrade_screen_why_title">مزایای ارتقا</string>
|
<string name="upgrade_screen_why_title">مزایای ارتقا</string>
|
||||||
<string name="upgrade_screen_how_title">چگونه کمک کنیم</string>
|
<string name="upgrade_screen_how_title">چگونه کمک کنیم</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Lahjoita</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Olen jo lahjoittanut</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Käytän kaikki rahani AirPodeihin</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS on ilmainen ja avoimen lähdekoodin ohjelma. Jos löydät sen hyödylliseksi, harkitse kehityksen tukemista projektin elässä pitämiseksi.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS on ilmainen ja avoimen lähdekoodin ohjelma. Jos löydät sen hyödylliseksi, harkitse kehityksen tukemista projektin elässä pitämiseksi.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Sponsoroi kehitystä</string>
|
<string name="upgrade_foss_sponsor_action">Sponsoroi kehitystä</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Ei mainoksia. Ei seurantaa. Ei Google Play -riippuvuutta.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Ei mainoksia. Ei seurantaa. Ei Google Play -riippuvuutta.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Tukija %s lähtien</string>
|
<string name="upgrade_foss_supporter_since">Tukija %s lähtien</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Kiitos, että tuet CAPodin kehitystä!</string>
|
<string name="upgrade_foss_supporter_thanks">Kiitos, että tuet CAPodin kehitystä!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Avaa sponsorisivu</string>
|
<string name="upgrade_foss_sponsor_again_action">Avaa sponsorisivu</string>
|
||||||
<string name="settings_upgrade_status_label">Tue CAPodia</string>
|
<string name="upgrade_foss_sponsor_label">Tue CAPodia</string>
|
||||||
<string name="settings_upgrade_status_description">Kannattajantila</string>
|
<string name="settings_upgrade_status_description">Kannattajantila</string>
|
||||||
<string name="upgrade_screen_why_title">Päivityksen edut</string>
|
<string name="upgrade_screen_why_title">Päivityksen edut</string>
|
||||||
<string name="upgrade_screen_how_title">Kuinka auttaa</string>
|
<string name="upgrade_screen_how_title">Kuinka auttaa</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Mag-donate</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Nakapag-donate na ako</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Ginagastos ko lahat ng pera ko sa AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">Ang CAPod FOSS ay libre at open source. Kung nakita mong kapaki-pakinabang ito, isaalang-alang ang pag-sponsor ng development para mapanatiling aktibo ang proyekto.</string>
|
<string name="upgrade_foss_preamble">Ang CAPod FOSS ay libre at open source. Kung nakita mong kapaki-pakinabang ito, isaalang-alang ang pag-sponsor ng development para mapanatiling aktibo ang proyekto.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Mag-sponsor ng development</string>
|
<string name="upgrade_foss_sponsor_action">Mag-sponsor ng development</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Walang ads. Walang tracking. Walang Google Play lock-in.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Walang ads. Walang tracking. Walang Google Play lock-in.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Tagasuporta simula %s</string>
|
<string name="upgrade_foss_supporter_since">Tagasuporta simula %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Salamat sa pagsuporta sa development ng CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Salamat sa pagsuporta sa development ng CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Buksan ang sponsor page</string>
|
<string name="upgrade_foss_sponsor_again_action">Buksan ang sponsor page</string>
|
||||||
<string name="settings_upgrade_status_label">Suportahan ang CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Suportahan ang CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Ang iyong status bilang supporter.</string>
|
<string name="settings_upgrade_status_description">Ang iyong status bilang supporter.</string>
|
||||||
<string name="upgrade_screen_why_title">Mga benepisyo ng upgrade</string>
|
<string name="upgrade_screen_why_title">Mga benepisyo ng upgrade</string>
|
||||||
<string name="upgrade_screen_how_title">Paano tumulong</string>
|
<string name="upgrade_screen_how_title">Paano tumulong</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Faire un don</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">J’ai déjà fait un don</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">J’ai dépensé tout mon argent sur des AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS est gratuite et à code source ouvert. Si vous la trouvez utile, pensez à soutenir le développement pour contribuer à la pérennité du projet.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS est gratuite et à code source ouvert. Si vous la trouvez utile, pensez à soutenir le développement pour contribuer à la pérennité du projet.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Soutenir le développement</string>
|
<string name="upgrade_foss_sponsor_action">Soutenir le développement</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Pas de publicités. Pas de suivi à la trace. Pas de dépendance à Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Pas de publicités. Pas de suivi à la trace. Pas de dépendance à Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Soutien depuis %s</string>
|
<string name="upgrade_foss_supporter_since">Soutien depuis %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Merci de soutenir le développement de CAPod !</string>
|
<string name="upgrade_foss_supporter_thanks">Merci de soutenir le développement de CAPod !</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Ouvrir la page de parrainage</string>
|
<string name="upgrade_foss_sponsor_again_action">Ouvrir la page de parrainage</string>
|
||||||
<string name="settings_upgrade_status_label">Soutenir CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Soutenir CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Votre statut de supporter.</string>
|
<string name="settings_upgrade_status_description">Votre statut de supporter.</string>
|
||||||
<string name="upgrade_screen_why_title">Avantages de la mise à niveau</string>
|
<string name="upgrade_screen_why_title">Avantages de la mise à niveau</string>
|
||||||
<string name="upgrade_screen_how_title">Comment aider</string>
|
<string name="upgrade_screen_how_title">Comment aider</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Doar</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Xa doei</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Gasto todos os meus cartos en AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS é gratuito e de código aberto. Se o atopas útil, considera patrocinar o desenvolvemento para axudar a manter o proxecto en marcha.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS é gratuito e de código aberto. Se o atopas útil, considera patrocinar o desenvolvemento para axudar a manter o proxecto en marcha.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Patrocinar desenvolvemento</string>
|
<string name="upgrade_foss_sponsor_action">Patrocinar desenvolvemento</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Sen anuncios. Sen rastrexo. Sen dependencia de Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Sen anuncios. Sen rastrexo. Sen dependencia de Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Colaborador desde %s</string>
|
<string name="upgrade_foss_supporter_since">Colaborador desde %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Grazas por apoiar o desenvolvemento de CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Grazas por apoiar o desenvolvemento de CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Abrir a páxina de patrocinio</string>
|
<string name="upgrade_foss_sponsor_again_action">Abrir a páxina de patrocinio</string>
|
||||||
<string name="settings_upgrade_status_label">Apoia CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Apoia CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">O teu estado de apoiador.</string>
|
<string name="settings_upgrade_status_description">O teu estado de apoiador.</string>
|
||||||
<string name="upgrade_screen_why_title">Vantaxes da actualización</string>
|
<string name="upgrade_screen_why_title">Vantaxes da actualización</string>
|
||||||
<string name="upgrade_screen_how_title">Como axudar</string>
|
<string name="upgrade_screen_how_title">Como axudar</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">दान करें</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">मैंने पहले ही दान कर दिया है</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">मैं अपना सारा पैसा AirPods पर खर्च करता हूं</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS मुफ्त और ओपन सोर्स है। यदि आपको यह उपयोगी लगता है, तो प्रोजेक्ट को जारी रखने में मदद के लिए विकास को प्रायोजित करने पर विचार करें।</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS मुफ्त और ओपन सोर्स है। यदि आपको यह उपयोगी लगता है, तो प्रोजेक्ट को जारी रखने में मदद के लिए विकास को प्रायोजित करने पर विचार करें।</string>
|
||||||
<string name="upgrade_foss_sponsor_action">विकास को प्रायोजक करें</string>
|
<string name="upgrade_foss_sponsor_action">विकास को प्रायोजक करें</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">कोई विज्ञापन नहीं। कोई ट्रैकिंग नहीं। Google Play पर निर्भरता नहीं।</string>
|
<string name="upgrade_foss_sponsor_subtitle">कोई विज्ञापन नहीं। कोई ट्रैकिंग नहीं। Google Play पर निर्भरता नहीं।</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">%s से समर्थक</string>
|
<string name="upgrade_foss_supporter_since">%s से समर्थक</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">CAPod के विकास का समर्थन करने के लिए धन्यवाद!</string>
|
<string name="upgrade_foss_supporter_thanks">CAPod के विकास का समर्थन करने के लिए धन्यवाद!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">स्पॉन्सर पेज खोलें</string>
|
<string name="upgrade_foss_sponsor_again_action">स्पॉन्सर पेज खोलें</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod को प्रायोजित करें</string>
|
<string name="upgrade_foss_sponsor_label">CAPod को प्रायोजित करें</string>
|
||||||
<string name="settings_upgrade_status_description">आपकी समर्थक स्थिति।</string>
|
<string name="settings_upgrade_status_description">आपकी समर्थक स्थिति।</string>
|
||||||
<string name="upgrade_screen_why_title">अपग्रेड के लाभ</string>
|
<string name="upgrade_screen_why_title">अपग्रेड के लाभ</string>
|
||||||
<string name="upgrade_screen_how_title">कैसे सहायता करें</string>
|
<string name="upgrade_screen_how_title">कैसे सहायता करें</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Donirajte</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Već sam donirao</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Sav svoj novac trošim na AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS je besplatan i otvorenog koda. Ako vam je koristan, razmislite o sponzoriranju razvoja kako bi projekt ostao živ.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS je besplatan i otvorenog koda. Ako vam je koristan, razmislite o sponzoriranju razvoja kako bi projekt ostao živ.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Podržite razvoj</string>
|
<string name="upgrade_foss_sponsor_action">Podržite razvoj</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Bez oglasa. Bez praćenja. Bez zaključanosti na Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Bez oglasa. Bez praćenja. Bez zaključanosti na Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Podržavatelj od %s</string>
|
<string name="upgrade_foss_supporter_since">Podržavatelj od %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Hvala vam što podržavate razvoj CAPoda!</string>
|
<string name="upgrade_foss_supporter_thanks">Hvala vam što podržavate razvoj CAPoda!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Otvori stranicu za sponzoriranje</string>
|
<string name="upgrade_foss_sponsor_again_action">Otvori stranicu za sponzoriranje</string>
|
||||||
<string name="settings_upgrade_status_label">Sponzorirajte CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Sponzorirajte CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Vaš status sponzora</string>
|
<string name="settings_upgrade_status_description">Vaš status sponzora</string>
|
||||||
<string name="upgrade_screen_why_title">Prednosti nadogradnje</string>
|
<string name="upgrade_screen_why_title">Prednosti nadogradnje</string>
|
||||||
<string name="upgrade_screen_how_title">Kako pomoći</string>
|
<string name="upgrade_screen_how_title">Kako pomoći</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Adományoz</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Már adományoztam</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Minden pénzemet az AirPods-ra költöttem</string>
|
|
||||||
<string name="upgrade_foss_preamble">A CAPod FOSS ingyenes és nyílt forráskódú. Ha hasznosnak találod, fontold meg a fejlesztés támogatását, hogy a projekt tovább élhessen.</string>
|
<string name="upgrade_foss_preamble">A CAPod FOSS ingyenes és nyílt forráskódú. Ha hasznosnak találod, fontold meg a fejlesztés támogatását, hogy a projekt tovább élhessen.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Szponzori fejlesztés</string>
|
<string name="upgrade_foss_sponsor_action">Szponzori fejlesztés</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Nincs hirdetés. Nincs nyomkövetés. Nincs Google Play-függőség.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Nincs hirdetés. Nincs nyomkövetés. Nincs Google Play-függőség.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Támogató %s óta</string>
|
<string name="upgrade_foss_supporter_since">Támogató %s óta</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Köszönjük, hogy támogatod a CAPod fejlesztését!</string>
|
<string name="upgrade_foss_supporter_thanks">Köszönjük, hogy támogatod a CAPod fejlesztését!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Támogatói oldal megnyitása</string>
|
<string name="upgrade_foss_sponsor_again_action">Támogatói oldal megnyitása</string>
|
||||||
<string name="settings_upgrade_status_label">Támogasson CAPod-ot</string>
|
<string name="upgrade_foss_sponsor_label">Támogasson CAPod-ot</string>
|
||||||
<string name="settings_upgrade_status_description">Az Ön támogató státusza.</string>
|
<string name="settings_upgrade_status_description">Az Ön támogató státusza.</string>
|
||||||
<string name="upgrade_screen_why_title">Frissítési előnyök</string>
|
<string name="upgrade_screen_why_title">Frissítési előnyök</string>
|
||||||
<string name="upgrade_screen_how_title">Hogyan lehet segíteni</string>
|
<string name="upgrade_screen_how_title">Hogyan lehet segíteni</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Նվիրաբերել</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Ես արդեն նվիրաբերել եմ</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Ես իմ ամբողջ գումարը ծախսում եմ AirPods-ի վրա</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS անվճար և բաց կոդով: Այն ոգտակար էք, խնդրում զարգացությունը կենդանի պահելու համար:</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS անվճար և բաց կոդով: Այն ոգտակար էք, խնդրում զարգացությունը կենդանի պահելու համար:</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Հովանավորել զարգացումը</string>
|
<string name="upgrade_foss_sponsor_action">Հովանավորել զարգացումը</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Լրատնություն չկա: հետքխկություն չկա: Google Play-ի կապվածություն չկա:</string>
|
<string name="upgrade_foss_sponsor_subtitle">Լրատնություն չկա: հետքխկություն չկա: Google Play-ի կապվածություն չկա:</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Հովանավոր է %s-ից</string>
|
<string name="upgrade_foss_supporter_since">Հովանավոր է %s-ից</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Շնորհակալություն CAPod-ի զարգացումն աջակցելու համար!</string>
|
<string name="upgrade_foss_supporter_thanks">Շնորհակալություն CAPod-ի զարգացումն աջակցելու համար!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Բացել հովանավորության էջը</string>
|
<string name="upgrade_foss_sponsor_again_action">Բացել հովանավորության էջը</string>
|
||||||
<string name="settings_upgrade_status_label">Աջակեք CAPod-ին</string>
|
<string name="upgrade_foss_sponsor_label">Աջակեք CAPod-ին</string>
|
||||||
<string name="settings_upgrade_status_description">Ձեր աջակցողի վիճակը:</string>
|
<string name="settings_upgrade_status_description">Ձեր աջակցողի վիճակը:</string>
|
||||||
<string name="upgrade_screen_why_title">Թարմացման առավելությունները</string>
|
<string name="upgrade_screen_why_title">Թարմացման առավելությունները</string>
|
||||||
<string name="upgrade_screen_how_title">Ինչպես օգնել</string>
|
<string name="upgrade_screen_how_title">Ինչպես օգնել</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Menyumbang</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Saya telah berdonasi</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Saya menghabiskan semua uang saya untuk AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS gratis dan sumber terbuka. Jika Anda merasa bermanfaat, pertimbangkan untuk mensponsori pengembangan guna menjaga proyek ini berjalan.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS gratis dan sumber terbuka. Jika Anda merasa bermanfaat, pertimbangkan untuk mensponsori pengembangan guna menjaga proyek ini berjalan.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Pengembangan sponsor</string>
|
<string name="upgrade_foss_sponsor_action">Pengembangan sponsor</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Tanpa iklan. Tanpa pelacakan. Tanpa ketergantungan Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Tanpa iklan. Tanpa pelacakan. Tanpa ketergantungan Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Pendukung sejak %s</string>
|
<string name="upgrade_foss_supporter_since">Pendukung sejak %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Terima kasih karena telah mendukung pengembangan CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Terima kasih karena telah mendukung pengembangan CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Buka halaman sponsor</string>
|
<string name="upgrade_foss_sponsor_again_action">Buka halaman sponsor</string>
|
||||||
<string name="settings_upgrade_status_label">Sponsori CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Sponsori CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Status pendukung Anda.</string>
|
<string name="settings_upgrade_status_description">Status pendukung Anda.</string>
|
||||||
<string name="upgrade_screen_why_title">Manfaat upgrade</string>
|
<string name="upgrade_screen_why_title">Manfaat upgrade</string>
|
||||||
<string name="upgrade_screen_how_title">Cara membantu</string>
|
<string name="upgrade_screen_how_title">Cara membantu</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Gefa</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Ég hef þegar gefið</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Ég eyði öllum peningunum mínum í AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS er ókeypis og opinn kóði. Ef þú finnur það gagnlegt, þakkaðu þér fyrir að stuðla að þróun til að hjálpa til við að halda verkefninu gangandi.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS er ókeypis og opinn kóði. Ef þú finnur það gagnlegt, þakkaðu þér fyrir að stuðla að þróun til að hjálpa til við að halda verkefninu gangandi.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Styrkja þróun</string>
|
<string name="upgrade_foss_sponsor_action">Styrkja þróun</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Engar auglysíngar. Engin rakning. Ekkert Google Play-lás.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Engar auglysíngar. Engin rakning. Ekkert Google Play-lás.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Styrktaraðili síðan %s</string>
|
<string name="upgrade_foss_supporter_since">Styrktaraðili síðan %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Takk fyrir að styðja þróun CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Takk fyrir að styðja þróun CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Opna styrktarsíðu</string>
|
<string name="upgrade_foss_sponsor_again_action">Opna styrktarsíðu</string>
|
||||||
<string name="settings_upgrade_status_label">Styrktu CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Styrktu CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Staða þín sem stuðningsmaður</string>
|
<string name="settings_upgrade_status_description">Staða þín sem stuðningsmaður</string>
|
||||||
<string name="upgrade_screen_why_title">Uppfærslukostir</string>
|
<string name="upgrade_screen_why_title">Uppfærslukostir</string>
|
||||||
<string name="upgrade_screen_how_title">Hvernig á að hjálpa</string>
|
<string name="upgrade_screen_how_title">Hvernig á að hjálpa</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Dona</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Ho già donato</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Spendo tutti i miei soldi per gli AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS è gratuito e open source. Se lo trovi utile, considera di sponsorizzare lo sviluppo per contribuire a mantenere il progetto in vita.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS è gratuito e open source. Se lo trovi utile, considera di sponsorizzare lo sviluppo per contribuire a mantenere il progetto in vita.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Finanzia lo sviluppo</string>
|
<string name="upgrade_foss_sponsor_action">Finanzia lo sviluppo</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Nessuna pubblicità. Nessun tracciamento. Nessun vincolo con Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Nessuna pubblicità. Nessun tracciamento. Nessun vincolo con Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Sostenitore dal %s</string>
|
<string name="upgrade_foss_supporter_since">Sostenitore dal %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Grazie per supportare lo sviluppo di CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Grazie per supportare lo sviluppo di CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Apri la pagina sponsor</string>
|
<string name="upgrade_foss_sponsor_again_action">Apri la pagina sponsor</string>
|
||||||
<string name="settings_upgrade_status_label">Sponsorizza CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Sponsorizza CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Il tuo status di sostenitore.</string>
|
<string name="settings_upgrade_status_description">Il tuo status di sostenitore.</string>
|
||||||
<string name="upgrade_screen_why_title">Vantaggi dell\'aggiornamento</string>
|
<string name="upgrade_screen_why_title">Vantaggi dell\'aggiornamento</string>
|
||||||
<string name="upgrade_screen_how_title">Come aiutare</string>
|
<string name="upgrade_screen_how_title">Come aiutare</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">תרומה</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">כבר תרמתי</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">מיטב כספי מושקע ב-AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS הוא חינם וקוד פתוח. אם הוא שימושי לך, שקול לשקול על חסוי הפיתוח כדי לעזור להמשיך את הפרויקט.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS הוא חינם וקוד פתוח. אם הוא שימושי לך, שקול לשקול על חסוי הפיתוח כדי לעזור להמשיך את הפרויקט.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">פיתוח חסות</string>
|
<string name="upgrade_foss_sponsor_action">פיתוח חסות</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">אין פרסומות. אין מעקב. אין תלות ב-Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">אין פרסומות. אין מעקב. אין תלות ב-Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">תומך מאז %s</string>
|
<string name="upgrade_foss_supporter_since">תומך מאז %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">תודה שאתה תומך בפיתוח של CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">תודה שאתה תומך בפיתוח של CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">פתח את דף התמיכה</string>
|
<string name="upgrade_foss_sponsor_again_action">פתח את דף התמיכה</string>
|
||||||
<string name="settings_upgrade_status_label">תמוך ב-CAPod</string>
|
<string name="upgrade_foss_sponsor_label">תמוך ב-CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">סטטוס התומך שלך.</string>
|
<string name="settings_upgrade_status_description">סטטוס התומך שלך.</string>
|
||||||
<string name="upgrade_screen_why_title">יתרונות השדרוג</string>
|
<string name="upgrade_screen_why_title">יתרונות השדרוג</string>
|
||||||
<string name="upgrade_screen_how_title">איך לעזור</string>
|
<string name="upgrade_screen_how_title">איך לעזור</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">寄付</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">すでに寄付しました</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">AirPodsに全財産をつぎ込んでいます</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSSは無料かつオープンソースです。便利だと思ったら、プロジェクトの継続に向けて開発をスポンサーすることをご検討ください。</string>
|
<string name="upgrade_foss_preamble">CAPod FOSSは無料かつオープンソースです。便利だと思ったら、プロジェクトの継続に向けて開発をスポンサーすることをご検討ください。</string>
|
||||||
<string name="upgrade_foss_sponsor_action">開発支援者</string>
|
<string name="upgrade_foss_sponsor_action">開発支援者</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">広告なし。追跡なし。Google Play依存なし。</string>
|
<string name="upgrade_foss_sponsor_subtitle">広告なし。追跡なし。Google Play依存なし。</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">%sからのサポーター</string>
|
<string name="upgrade_foss_supporter_since">%sからのサポーター</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">CAPodの開発を支援していただきありがとうございます!</string>
|
<string name="upgrade_foss_supporter_thanks">CAPodの開発を支援していただきありがとうございます!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">スポンサーページを開く</string>
|
<string name="upgrade_foss_sponsor_again_action">スポンサーページを開く</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod をスポンサーする</string>
|
<string name="upgrade_foss_sponsor_label">CAPod をスポンサーする</string>
|
||||||
<string name="settings_upgrade_status_description">サポーターステータス。</string>
|
<string name="settings_upgrade_status_description">サポーターステータス。</string>
|
||||||
<string name="upgrade_screen_why_title">アップグレードの特典</string>
|
<string name="upgrade_screen_why_title">アップグレードの特典</string>
|
||||||
<string name="upgrade_screen_how_title">協力するには</string>
|
<string name="upgrade_screen_how_title">協力するには</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">შემოწირულობა</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">მე უკვე შემოწირული მაქვს</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">მთელ ჩემს ფულს AirPods-ებზე ვხარჯავ</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS უფასოა და ღია წყაროა. თუ გსარგებლია, გაანაბრეთ განვითარება პროექტის გადასაგრელად.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS უფასოა და ღია წყაროა. თუ გსარგებლია, გაანაბრეთ განვითარება პროექტის გადასაგრელად.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">სპონსორის განვითარება</string>
|
<string name="upgrade_foss_sponsor_action">სპონსორის განვითარება</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">რეკლამა არა. თვალთვალება არა. Google Play-ზე დამოკიდება არა.</string>
|
<string name="upgrade_foss_sponsor_subtitle">რეკლამა არა. თვალთვალება არა. Google Play-ზე დამოკიდება არა.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">მხარდამჭერი %s-დან</string>
|
<string name="upgrade_foss_supporter_since">მხარდამჭერი %s-დან</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">მადლობა CAPod-ის განვითარების მხარდაჭერისთვის!</string>
|
<string name="upgrade_foss_supporter_thanks">მადლობა CAPod-ის განვითარების მხარდაჭერისთვის!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">სპონსორის გვერდის გახსნა</string>
|
<string name="upgrade_foss_sponsor_again_action">სპონსორის გვერდის გახსნა</string>
|
||||||
<string name="settings_upgrade_status_label">მხარი დაუჭიროთ CAPod-ს</string>
|
<string name="upgrade_foss_sponsor_label">მხარი დაუჭიროთ CAPod-ს</string>
|
||||||
<string name="settings_upgrade_status_description">თქვენი მხარდამჭერის მდგომარეობა.</string>
|
<string name="settings_upgrade_status_description">თქვენი მხარდამჭერის მდგომარეობა.</string>
|
||||||
<string name="upgrade_screen_why_title">განახლების უპირატესობები</string>
|
<string name="upgrade_screen_why_title">განახლების უპირატესობები</string>
|
||||||
<string name="upgrade_screen_how_title">როგორ დაგეხმაროთ</string>
|
<string name="upgrade_screen_how_title">როგორ დაგეხმაროთ</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">បរិច្ចាគ</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">ខ្ញុំបានបរិច្ចាគរួចហើយ</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">ខ្ញុំចំណាយលុយទាំងអស់របស់ខ្ញុំលើ AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS ជាកម្មវិធីឥតគិតថ្លៃ និងប្រភពបើកចំហ។ ប្រសិនបើអ្នករកហើញថ្លៃវាមានប្រយោជន៍ សូមពិចារណាឧបត្ថម្ភការអភិវឌ្ឍន៍ ដើម្បីជួយឥ្សរិយគម្រោងបន្តដំណើរការ។</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS ជាកម្មវិធីឥតគិតថ្លៃ និងប្រភពបើកចំហ។ ប្រសិនបើអ្នករកហើញថ្លៃវាមានប្រយោជន៍ សូមពិចារណាឧបត្ថម្ភការអភិវឌ្ឍន៍ ដើម្បីជួយឥ្សរិយគម្រោងបន្តដំណើរការ។</string>
|
||||||
<string name="upgrade_foss_sponsor_action">ឧបត្ថម្ភការអភិវឌ្ឍន៍</string>
|
<string name="upgrade_foss_sponsor_action">ឧបត្ថម្ភការអភិវឌ្ឍន៍</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">គ្មានការផ្សាយពាណិជ្ជកម្ម។ គ្មានការតាមដាន។ គ្មានការចាក់សោ Google Play។</string>
|
<string name="upgrade_foss_sponsor_subtitle">គ្មានការផ្សាយពាណិជ្ជកម្ម។ គ្មានការតាមដាន។ គ្មានការចាក់សោ Google Play។</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">អ្នកគាំទ្រតាំងពី %s</string>
|
<string name="upgrade_foss_supporter_since">អ្នកគាំទ្រតាំងពី %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">សូមអរគុណសម្រាប់ការគាំទ្រការអភិវឌ្ឍន៍ CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">សូមអរគុណសម្រាប់ការគាំទ្រការអភិវឌ្ឍន៍ CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">បើកទំព័រឧបត្ថម្ភ</string>
|
<string name="upgrade_foss_sponsor_again_action">បើកទំព័រឧបត្ថម្ភ</string>
|
||||||
<string name="settings_upgrade_status_label">ឧបត្ថម្ភ CAPod</string>
|
<string name="upgrade_foss_sponsor_label">ឧបត្ថម្ភ CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">ស្ថានភាពអ្នកគាំទ្ររបស់អ្នក។</string>
|
<string name="settings_upgrade_status_description">ស្ថានភាពអ្នកគាំទ្ររបស់អ្នក។</string>
|
||||||
<string name="upgrade_screen_why_title">អត្ថប្រយោជន៍លើកកម្ពស់</string>
|
<string name="upgrade_screen_why_title">អត្ថប្រយោជន៍លើកកម្ពស់</string>
|
||||||
<string name="upgrade_screen_how_title">របៀបជួយ</string>
|
<string name="upgrade_screen_how_title">របៀបជួយ</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Beşdar bike</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Min berê bexş kir</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Ez hemû pereyê xwe li AirPods xerc dikim</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS belaş û çavkaniya vekirî ye. Ger hûn wê kêrhastî dibînin, fikir bikin ku perkirezan bike da ku alîkariya berdewamî projeya bide.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS belaş û çavkaniya vekirî ye. Ger hûn wê kêrhastî dibînin, fikir bikin ku perkirezan bike da ku alîkariya berdewamî projeya bide.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Pêşdebiriyê teref bike</string>
|
<string name="upgrade_foss_sponsor_action">Pêşdebiriyê teref bike</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Reklam tune. Śopandin tune. Girêdana Google Play tune.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Reklam tune. Śopandin tune. Girêdana Google Play tune.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Piştgir ji %s ve</string>
|
<string name="upgrade_foss_supporter_since">Piştgir ji %s ve</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Spas ji bo piştgiriya te ya pêşxistina CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Spas ji bo piştgiriya te ya pêşxistina CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Rûpela piştgiriyê veke</string>
|
<string name="upgrade_foss_sponsor_again_action">Rûpela piştgiriyê veke</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod-ê piştgirî bike</string>
|
<string name="upgrade_foss_sponsor_label">CAPod-ê piştgirî bike</string>
|
||||||
<string name="settings_upgrade_status_description">Rewşa piştgiriya te.</string>
|
<string name="settings_upgrade_status_description">Rewşa piştgiriya te.</string>
|
||||||
<string name="upgrade_screen_why_title">Feydeyên Bardiyê</string>
|
<string name="upgrade_screen_why_title">Feydeyên Bardiyê</string>
|
||||||
<string name="upgrade_screen_how_title">Çawa Alîkarî Bike</string>
|
<string name="upgrade_screen_how_title">Çawa Alîkarî Bike</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">ದಾನ ಮಾಡಿ</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">ನಾನು ಈಗಾಗಲೇ ದಾನ ಮಾಡಿದ್ದೇನೆ</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">ನಾನು ನನ್ನ ಎಲ್ಲಾ ಹಣವನ್ನು AirPods ಗಾಗಿ ಖರ್ಚು ಮಾಡುತ್ತೇನೆ</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS ಉಚಿತ ಮತ್ತು ತೆರೆದ ಮೂಲದ್ದಾಗಿದೆ. ನಿಮಗೆ ಉಪಯುಕ್ತವಾಗಿ ತೋರಿದರೆ, ಯೋಜನೆಯನ್ನು ಮುಂದುವರಿಸಲು ಅಭಿವೃದ್ಧಿಗೆ ಪ್ರಾಯೋಜಕತ್ವ ನೀಡಲು ಪರಿಗಣಿಸಿ.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS ಉಚಿತ ಮತ್ತು ತೆರೆದ ಮೂಲದ್ದಾಗಿದೆ. ನಿಮಗೆ ಉಪಯುಕ್ತವಾಗಿ ತೋರಿದರೆ, ಯೋಜನೆಯನ್ನು ಮುಂದುವರಿಸಲು ಅಭಿವೃದ್ಧಿಗೆ ಪ್ರಾಯೋಜಕತ್ವ ನೀಡಲು ಪರಿಗಣಿಸಿ.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">ಅಭಿವೃದ್ಧಿಗೆ ಪ್ರಾಯೋಜಕತ್ವ ನೀಡಿ</string>
|
<string name="upgrade_foss_sponsor_action">ಅಭಿವೃದ್ಧಿಗೆ ಪ್ರಾಯೋಜಕತ್ವ ನೀಡಿ</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">ಜಾಹೀರಾತುಗಳಿಲ್ಲ. ಭಕ್ಷಣೆ ಇಲ್ಲ. Google Play ಲಾಕ್-ಇನ್ ಇಲ್ಲ.</string>
|
<string name="upgrade_foss_sponsor_subtitle">ಜಾಹೀರಾತುಗಳಿಲ್ಲ. ಭಕ್ಷಣೆ ಇಲ್ಲ. Google Play ಲಾಕ್-ಇನ್ ಇಲ್ಲ.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">%s ರಿಂದ ಬೆಂಬಲಿಗ</string>
|
<string name="upgrade_foss_supporter_since">%s ರಿಂದ ಬೆಂಬಲಿಗ</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">CAPod ಅಭಿವೃದ್ಧಿಗೆ ಬೆಂಬಲ ನೀಡಿದ್ದಕ್ಕಾಗಿ ಧನ್ಯವಾದಗಳು!</string>
|
<string name="upgrade_foss_supporter_thanks">CAPod ಅಭಿವೃದ್ಧಿಗೆ ಬೆಂಬಲ ನೀಡಿದ್ದಕ್ಕಾಗಿ ಧನ್ಯವಾದಗಳು!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">ಪ್ರಾಯೋಜಕ ಪುಟ ತೆರೆಯಿರಿ</string>
|
<string name="upgrade_foss_sponsor_again_action">ಪ್ರಾಯೋಜಕ ಪುಟ ತೆರೆಯಿರಿ</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod ಬೆಂಬಲಿಸಿ</string>
|
<string name="upgrade_foss_sponsor_label">CAPod ಬೆಂಬಲಿಸಿ</string>
|
||||||
<string name="settings_upgrade_status_description">ನಿಮ್ಮ ಬೆಂಬಲಕಾರ ಸ್ಥಿತಿ.</string>
|
<string name="settings_upgrade_status_description">ನಿಮ್ಮ ಬೆಂಬಲಕಾರ ಸ್ಥಿತಿ.</string>
|
||||||
<string name="upgrade_screen_why_title">ನವೀಕರಣ ಪ್ರಯೋಜನಗಳು</string>
|
<string name="upgrade_screen_why_title">ನವೀಕರಣ ಪ್ರಯೋಜನಗಳು</string>
|
||||||
<string name="upgrade_screen_how_title">ಸಹಾಯ ಮಾಡುವುದು ಹೇಗೆ</string>
|
<string name="upgrade_screen_how_title">ಸಹಾಯ ಮಾಡುವುದು ಹೇಗೆ</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">후원하기</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">이미 후원했어요</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">AirPods에 돈을 다 썼어요</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS는 무료 오픈소스입니다. 유용하게 사용하고 계신다면 프로젝트 유지에 도움이 되도록 후원을 고려해 주세요.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS는 무료 오픈소스입니다. 유용하게 사용하고 계신다면 프로젝트 유지에 도움이 되도록 후원을 고려해 주세요.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">개발 후원하기</string>
|
<string name="upgrade_foss_sponsor_action">개발 후원하기</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">광고 없음. 추적 없음. Google Play 의존 없음.</string>
|
<string name="upgrade_foss_sponsor_subtitle">광고 없음. 추적 없음. Google Play 의존 없음.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">%s부터 후원자</string>
|
<string name="upgrade_foss_supporter_since">%s부터 후원자</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">CAPod 개발을 후원해 주셔서 감사합니다!</string>
|
<string name="upgrade_foss_supporter_thanks">CAPod 개발을 후원해 주셔서 감사합니다!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">후원 페이지 열기</string>
|
<string name="upgrade_foss_sponsor_again_action">후원 페이지 열기</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod 후원하기</string>
|
<string name="upgrade_foss_sponsor_label">CAPod 후원하기</string>
|
||||||
<string name="settings_upgrade_status_description">후원자 상태</string>
|
<string name="settings_upgrade_status_description">후원자 상태</string>
|
||||||
<string name="upgrade_screen_why_title">업그레이드 혜택</string>
|
<string name="upgrade_screen_why_title">업그레이드 혜택</string>
|
||||||
<string name="upgrade_screen_how_title">도움 주기</string>
|
<string name="upgrade_screen_how_title">도움 주기</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Демөөрчүлүк кылуу</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Мен буга чейин демөөрчүлүк кылгам</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Мен бүт акчамды AirPods үчүн короттум</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS беплатан жана ачык каттулууда. Егер пайдалуу таапсаңыз, жобаны улантырууга колдоо көрсөтүңүз.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS беплатан жана ачык каттулууда. Егер пайдалуу таапсаңыз, жобаны улантырууга колдоо көрсөтүңүз.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Иштелеп чыгууну колдоо</string>
|
<string name="upgrade_foss_sponsor_action">Иштелеп чыгууну колдоо</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Жарнама. Кадалоолоо жок. Google Playга байланма.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Жарнама. Кадалоолоо жок. Google Playга байланма.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">%s\'дан бери колдоочу</string>
|
<string name="upgrade_foss_supporter_since">%s\'дан бери колдоочу</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">CAPod\'дун өнүгүшүн колдогонуңуз үчүн рахмат!</string>
|
<string name="upgrade_foss_supporter_thanks">CAPod\'дун өнүгүшүн колдогонуңуз үчүн рахмат!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Демөөрчүлүк баракчасын ачуу</string>
|
<string name="upgrade_foss_sponsor_again_action">Демөөрчүлүк баракчасын ачуу</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod-ды спонсорлоо</string>
|
<string name="upgrade_foss_sponsor_label">CAPod-ды спонсорлоо</string>
|
||||||
<string name="settings_upgrade_status_description">Колдоочу абалы</string>
|
<string name="settings_upgrade_status_description">Колдоочу абалы</string>
|
||||||
<string name="upgrade_screen_why_title">Жогорулоонун пайдалары</string>
|
<string name="upgrade_screen_why_title">Жогорулоонун пайдалары</string>
|
||||||
<string name="upgrade_screen_how_title">Жардам бергүүнүн жолу</string>
|
<string name="upgrade_screen_how_title">Жардам бергүүнүн жолу</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">ບໍລິຈາກ</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">ຂ້ອຍໄດ້ບໍລິຈາກແລ້ວ</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">ຂ້ອຍໃຊ້ເງິນທັງໝົດຂອງຂ້ອຍໃສ່ AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS ແມ່ນຟຣີ ແລະ ໂອເພນຊອດ. ຖ້າທ່ານເຫັນວ່າມີປະໂຫຍດ, ພິຈາລະນາສະໜັບສະໜູນການພັດທະນາເພື່ອຊ່ວຍໃຫ້ໂຄງການດຳເນີນຕໍ່ໄປ.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS ແມ່ນຟຣີ ແລະ ໂອເພນຊອດ. ຖ້າທ່ານເຫັນວ່າມີປະໂຫຍດ, ພິຈາລະນາສະໜັບສະໜູນການພັດທະນາເພື່ອຊ່ວຍໃຫ້ໂຄງການດຳເນີນຕໍ່ໄປ.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">ສະໜັບສະໜູນການພັດທະນາ</string>
|
<string name="upgrade_foss_sponsor_action">ສະໜັບສະໜູນການພັດທະນາ</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">ບໍ່ມີໂຄສະນາ. ບໍ່ມີການຕິດຕາມ. ບໍ່ຕິດ Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">ບໍ່ມີໂຄສະນາ. ບໍ່ມີການຕິດຕາມ. ບໍ່ຕິດ Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">ຜູ້ສະໜັບສະໜູນຕັ້ງແຕ່ %s</string>
|
<string name="upgrade_foss_supporter_since">ຜູ້ສະໜັບສະໜູນຕັ້ງແຕ່ %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">ຂອບຊູ່ສຳລັບການສະໜັບສະໜູນການພັດທະນາຂອງ CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">ຂອບຊູ່ສຳລັບການສະໜັບສະໜູນການພັດທະນາຂອງ CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">ເປິດໝ້າສະໜັບສະໜູນ</string>
|
<string name="upgrade_foss_sponsor_again_action">ເປິດໝ້າສະໜັບສະໜູນ</string>
|
||||||
<string name="settings_upgrade_status_label">ສະໜັບສະໜູນ CAPod</string>
|
<string name="upgrade_foss_sponsor_label">ສະໜັບສະໜູນ CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">ສະຖານະຜູ້ສະໜັບສະໜູນຂອງທ່ານ</string>
|
<string name="settings_upgrade_status_description">ສະຖານະຜູ້ສະໜັບສະໜູນຂອງທ່ານ</string>
|
||||||
<string name="upgrade_screen_why_title">ປະໂຫຍດຂອງການອັບເກຣດ</string>
|
<string name="upgrade_screen_why_title">ປະໂຫຍດຂອງການອັບເກຣດ</string>
|
||||||
<string name="upgrade_screen_how_title">ວິທີການຊ່ວຍເຫຼືອ</string>
|
<string name="upgrade_screen_how_title">ວິທີການຊ່ວຍເຫຼືອ</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Aukoti</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Aš jau paaukojau</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Visus savo pinigus išleidžiu „AirPods“ ausinėms</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS yra nemokama ir atviro kodo programa. Jei ji jums naudinga, pagalvokite apie rėmimą, kad projektą būtų galima tęsti.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS yra nemokama ir atviro kodo programa. Jei ji jums naudinga, pagalvokite apie rėmimą, kad projektą būtų galima tęsti.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Remti plėtrą</string>
|
<string name="upgrade_foss_sponsor_action">Remti plėtrą</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Jokių reklamų. Jokio sekimo. Jokio „Google Play“ priklausomybės.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Jokių reklamų. Jokio sekimo. Jokio „Google Play“ priklausomybės.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Rėmėjas nuo %s</string>
|
<string name="upgrade_foss_supporter_since">Rėmėjas nuo %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Ačiū, kad remiate CAPod kūrimą!</string>
|
<string name="upgrade_foss_supporter_thanks">Ačiū, kad remiate CAPod kūrimą!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Atidaryti rėmėjo puslapį</string>
|
<string name="upgrade_foss_sponsor_again_action">Atidaryti rėmėjo puslapį</string>
|
||||||
<string name="settings_upgrade_status_label">Remti CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Remti CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Jūsų rėmėjo statusas.</string>
|
<string name="settings_upgrade_status_description">Jūsų rėmėjo statusas.</string>
|
||||||
<string name="upgrade_screen_why_title">Atnaujinimo privalumai</string>
|
<string name="upgrade_screen_why_title">Atnaujinimo privalumai</string>
|
||||||
<string name="upgrade_screen_how_title">Kaip padėti</string>
|
<string name="upgrade_screen_how_title">Kaip padėti</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Ziedot</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Es jau ziedoju</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Es iztērēju visu savu naudu AirPods austiņām</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS ir bezmaksas un atkļējkoda. Ja tā ir noderba, apsveriet attīstības sponsēšanu, lai palīdzētu turpināt projektu.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS ir bezmaksas un atkļējkoda. Ja tā ir noderba, apsveriet attīstības sponsēšanu, lai palīdzētu turpināt projektu.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Sponsorēt attīstību</string>
|
<string name="upgrade_foss_sponsor_action">Sponsorēt attīstību</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Bez reklamām. Bez izsekošanas. Bez Google Play saistībām.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Bez reklamām. Bez izsekošanas. Bez Google Play saistībām.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Atbalstītājs kopš %s</string>
|
<string name="upgrade_foss_supporter_since">Atbalstītājs kopš %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Paldies, ka atbalsti CAPod izstrādi!</string>
|
<string name="upgrade_foss_supporter_thanks">Paldies, ka atbalsti CAPod izstrādi!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Atvērt sponsorēšanas lapu</string>
|
<string name="upgrade_foss_sponsor_again_action">Atvērt sponsorēšanas lapu</string>
|
||||||
<string name="settings_upgrade_status_label">Atbalstīt CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Atbalstīt CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Jūsu atbalstītāja statuss.</string>
|
<string name="settings_upgrade_status_description">Jūsu atbalstītāja statuss.</string>
|
||||||
<string name="upgrade_screen_why_title">Jaunināšanas priekšrocības</string>
|
<string name="upgrade_screen_why_title">Jaunināšanas priekšrocības</string>
|
||||||
<string name="upgrade_screen_how_title">Kā palīdzēt</string>
|
<string name="upgrade_screen_how_title">Kā palīdzēt</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Донирај</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Веќе донирав</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Ги трошам сите пари на AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS е бесплатен и отворен код. Ако ви е корисен, размислете да го спонзорирате развојот за да помогнете проектот да продолжи.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS е бесплатен и отворен код. Ако ви е корисен, размислете да го спонзорирате развојот за да помогнете проектот да продолжи.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Спонзорирај развој</string>
|
<string name="upgrade_foss_sponsor_action">Спонзорирај развој</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Без реклами. Без пратење. Без зависност од Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Без реклами. Без пратење. Без зависност од Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Поддржувач од %s</string>
|
<string name="upgrade_foss_supporter_since">Поддржувач од %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Ти благодариме што го поддржуваш развојот на CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Ти благодариме што го поддржуваш развојот на CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Отвори ја страницата за спонзорство</string>
|
<string name="upgrade_foss_sponsor_again_action">Отвори ја страницата за спонзорство</string>
|
||||||
<string name="settings_upgrade_status_label">Поддржи CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Поддржи CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Твојот статус на поддржувач.</string>
|
<string name="settings_upgrade_status_description">Твојот статус на поддржувач.</string>
|
||||||
<string name="upgrade_screen_why_title">Предности на надградување</string>
|
<string name="upgrade_screen_why_title">Предности на надградување</string>
|
||||||
<string name="upgrade_screen_how_title">Како да помогнете</string>
|
<string name="upgrade_screen_how_title">Како да помогнете</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">സംഭാവന ചെയ്യുക</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">ഞാൻ ഇതിനകം സംഭാവന ചെയ്തു</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">ഞാൻ എൻ്റെ എല്ലാ പണവും AirPods-നായി ചെലവഴിക്കുന്നു</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS സൗജന്യവും ഓപ്പൻ സോഴ്സുമാണ്. നിങ്ങൾക്ക് ഇത് ഉപകാരപ്രദമാണെങ്കിൽ, പ്രോജെക്ട് തുടരാൻ സഹായിക്കുന്നതിന് ഡെവലപ്പ്മെന്റ് സ്പോൺസർ ചെയ്യുന്നത് പരിഗണിക്കുക.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS സൗജന്യവും ഓപ്പൻ സോഴ്സുമാണ്. നിങ്ങൾക്ക് ഇത് ഉപകാരപ്രദമാണെങ്കിൽ, പ്രോജെക്ട് തുടരാൻ സഹായിക്കുന്നതിന് ഡെവലപ്പ്മെന്റ് സ്പോൺസർ ചെയ്യുന്നത് പരിഗണിക്കുക.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">വികസനം സ്പോൺസർ ചെയ്യുക</string>
|
<string name="upgrade_foss_sponsor_action">വികസനം സ്പോൺസർ ചെയ്യുക</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">പരസ്യങ്ങൾ ഇല്ല. ട്രാക്കിംഗ് ഇല്ല. Google Play ലോക്ക്-ഇൻ ഇല്ല.</string>
|
<string name="upgrade_foss_sponsor_subtitle">പരസ്യങ്ങൾ ഇല്ല. ട്രാക്കിംഗ് ഇല്ല. Google Play ലോക്ക്-ഇൻ ഇല്ല.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">%s മുതൽ പിന്തുണക്കാൻ</string>
|
<string name="upgrade_foss_supporter_since">%s മുതൽ പിന്തുണക്കാൻ</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">CAPod-ന്റെ വികസനത്തെ പിന്തുണച്ചതിന് നന്ദി!</string>
|
<string name="upgrade_foss_supporter_thanks">CAPod-ന്റെ വികസനത്തെ പിന്തുണച്ചതിന് നന്ദി!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">സ്പോൺസർ പേജ് തുറക്കുക</string>
|
<string name="upgrade_foss_sponsor_again_action">സ്പോൺസർ പേജ് തുറക്കുക</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod നെ സ്പോൺസർ ചെയ്യുക</string>
|
<string name="upgrade_foss_sponsor_label">CAPod നെ സ്പോൺസർ ചെയ്യുക</string>
|
||||||
<string name="settings_upgrade_status_description">നിങ്ങളുടെ പിന്തുണയ സ്ഥിതി.</string>
|
<string name="settings_upgrade_status_description">നിങ്ങളുടെ പിന്തുണയ സ്ഥിതി.</string>
|
||||||
<string name="upgrade_screen_why_title">അപ്ഗ്രേഡ് നേട്ടങ്ങൾ</string>
|
<string name="upgrade_screen_why_title">അപ്ഗ്രേഡ് നേട്ടങ്ങൾ</string>
|
||||||
<string name="upgrade_screen_how_title">എങ്ങനെ സഹായിക്കാം</string>
|
<string name="upgrade_screen_how_title">എങ്ങനെ സഹായിക്കാം</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Хандивлах</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Би аль хэдийн хандивласан</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Би бүх мөнгөө AirPods-д зарцуулдаг</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS нь үнэгүй, нээлтэй эхийн програм. Хэрэв танд хэрэгтэй бол төслийг үргэлжүүлэхэд туслахын тулд хөгжүүлэлтийг дэмжих талаар бодоорой.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS нь үнэгүй, нээлтэй эхийн програм. Хэрэв танд хэрэгтэй бол төслийг үргэлжүүлэхэд туслахын тулд хөгжүүлэлтийг дэмжих талаар бодоорой.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Хөгжлийг дэмжих</string>
|
<string name="upgrade_foss_sponsor_action">Хөгжлийг дэмжих</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Реклам байхгүй. Хяналт байхгүй. Google Play-д хамааралгүй.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Реклам байхгүй. Хяналт байхгүй. Google Play-д хамааралгүй.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">%s-с хойш дэмжигч</string>
|
<string name="upgrade_foss_supporter_since">%s-с хойш дэмжигч</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">CAPod-ын хөгжлийг дэмжсэнд баярлалаа!</string>
|
<string name="upgrade_foss_supporter_thanks">CAPod-ын хөгжлийг дэмжсэнд баярлалаа!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Дэмжигчийн хуудсыг нээх</string>
|
<string name="upgrade_foss_sponsor_again_action">Дэмжигчийн хуудсыг нээх</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod-ыг спонсорлох</string>
|
<string name="upgrade_foss_sponsor_label">CAPod-ыг спонсорлох</string>
|
||||||
<string name="settings_upgrade_status_description">Таны дэмжигч статус.</string>
|
<string name="settings_upgrade_status_description">Таны дэмжигч статус.</string>
|
||||||
<string name="upgrade_screen_why_title">Давуу талууд</string>
|
<string name="upgrade_screen_why_title">Давуу талууд</string>
|
||||||
<string name="upgrade_screen_how_title">Хэрхэн тусламж үзүүлэх</string>
|
<string name="upgrade_screen_how_title">Хэрхэн тусламж үзүүлэх</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">दान करा</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">मी आधीच दान केले आहे</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">मी माझे सर्व पैसे AirPods वर खर्च करतो</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS विनामूल्य आणि ओपन सोर्स आहे. जर तुम्हाला ते उपयुक्त वाटत असेल, तर प्रकल्प सुरू ठेवण्यासाठी विकासास प्रायोजित करण्याचा विचार करा.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS विनामूल्य आणि ओपन सोर्स आहे. जर तुम्हाला ते उपयुक्त वाटत असेल, तर प्रकल्प सुरू ठेवण्यासाठी विकासास प्रायोजित करण्याचा विचार करा.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">विकासास प्रायोजित करा</string>
|
<string name="upgrade_foss_sponsor_action">विकासास प्रायोजित करा</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">कोणत्याही जाहिराती नाहीत. कोणतेही ट्रॅकिंग नाही. Google Play चे बंधन नाही.</string>
|
<string name="upgrade_foss_sponsor_subtitle">कोणत्याही जाहिराती नाहीत. कोणतेही ट्रॅकिंग नाही. Google Play चे बंधन नाही.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">%s पासून समर्थक</string>
|
<string name="upgrade_foss_supporter_since">%s पासून समर्थक</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">CAPod च्या विकासाला पाठिंबा दिल्याबद्दल धन्यवाद!</string>
|
<string name="upgrade_foss_supporter_thanks">CAPod च्या विकासाला पाठिंबा दिल्याबद्दल धन्यवाद!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">प्रायोजक पृष्ठ उघडा</string>
|
<string name="upgrade_foss_sponsor_again_action">प्रायोजक पृष्ठ उघडा</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod ला प्रायोजित करा</string>
|
<string name="upgrade_foss_sponsor_label">CAPod ला प्रायोजित करा</string>
|
||||||
<string name="settings_upgrade_status_description">आपल्या समर्थक स्थिती.</string>
|
<string name="settings_upgrade_status_description">आपल्या समर्थक स्थिती.</string>
|
||||||
<string name="upgrade_screen_why_title">अपग्रेड लाभ</string>
|
<string name="upgrade_screen_why_title">अपग्रेड लाभ</string>
|
||||||
<string name="upgrade_screen_how_title">मदत कसे करायची</string>
|
<string name="upgrade_screen_how_title">मदत कसे करायची</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Sumbang</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Saya telah menyumbang</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Saya belanjakan semua wang saya untuk AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS adalah percuma dan sumber terbuka. Jika anda mendapatinya berguna, pertimbangkan untuk menaja pembangunannya bagi membantu projek ini terus berjalan.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS adalah percuma dan sumber terbuka. Jika anda mendapatinya berguna, pertimbangkan untuk menaja pembangunannya bagi membantu projek ini terus berjalan.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Pembangunan penaja</string>
|
<string name="upgrade_foss_sponsor_action">Pembangunan penaja</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Tiada iklan. Tiada penjejakan. Tiada ikatan Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Tiada iklan. Tiada penjejakan. Tiada ikatan Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Penyokong sejak %s</string>
|
<string name="upgrade_foss_supporter_since">Penyokong sejak %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Terima kasih kerana menyokong pembangunan CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Terima kasih kerana menyokong pembangunan CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Buka halaman penaja</string>
|
<string name="upgrade_foss_sponsor_again_action">Buka halaman penaja</string>
|
||||||
<string name="settings_upgrade_status_label">Menajakan CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Menajakan CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Status penyokong anda.</string>
|
<string name="settings_upgrade_status_description">Status penyokong anda.</string>
|
||||||
<string name="upgrade_screen_why_title">Manfaat peningkatan</string>
|
<string name="upgrade_screen_why_title">Manfaat peningkatan</string>
|
||||||
<string name="upgrade_screen_how_title">Bagaimana untuk membantu</string>
|
<string name="upgrade_screen_how_title">Bagaimana untuk membantu</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">လှူဒါန်းပါ</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">ကျွန်တော် လှူပြီးပါပြီ</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">ကျွန်တော် ပိုက်ဆံအားလုံးကို AirPods မှာ သုံးတယ်</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS သည် အခမဲ့နှင့် open source ဖြစ်သည်။ အသုံးပြုခုပ်ဆည်းနိုင် အသားဖြစ်ပါက ပရာဗက်ဆက်လက်ရန် ဖွဲ့ဖြီးရေးကို ပံ့ပိုးပေးသည်။</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS သည် အခမဲ့နှင့် open source ဖြစ်သည်။ အသုံးပြုခုပ်ဆည်းနိုင် အသားဖြစ်ပါက ပရာဗက်ဆက်လက်ရန် ဖွဲ့ဖြီးရေးကို ပံ့ပိုးပေးသည်။</string>
|
||||||
<string name="upgrade_foss_sponsor_action">ဖွံ့ဖြိုးတိုးတက်မှုကို ကမကထပံ့ပိုးရန်</string>
|
<string name="upgrade_foss_sponsor_action">ဖွံ့ဖြိုးတိုးတက်မှုကို ကမကထပံ့ပိုးရန်</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">ကြောင်ညာမရှိ။ ခြေရာမခံ။ Google Play ချုပ်ချယ်မြုမရှိ။</string>
|
<string name="upgrade_foss_sponsor_subtitle">ကြောင်ညာမရှိ။ ခြေရာမခံ။ Google Play ချုပ်ချယ်မြုမရှိ။</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">%s မှစ၍ ပံ့ပိုးသူ</string>
|
<string name="upgrade_foss_supporter_since">%s မှစ၍ ပံ့ပိုးသူ</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">CAPod ၏ ဖွံ့ဖြိုးတိုးတက်မှုကို ပံ့ပိုးပေးသည့်အတွက် ကျေးဇူးတင်ပါသည်!</string>
|
<string name="upgrade_foss_supporter_thanks">CAPod ၏ ဖွံ့ဖြိုးတိုးတက်မှုကို ပံ့ပိုးပေးသည့်အတွက် ကျေးဇူးတင်ပါသည်!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">ပံ့ပိုးသူစာမျက်နှာကို ဖွင့်ပါ</string>
|
<string name="upgrade_foss_sponsor_again_action">ပံ့ပိုးသူစာမျက်နှာကို ဖွင့်ပါ</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod ကို ပံ့ပိုးပါ</string>
|
<string name="upgrade_foss_sponsor_label">CAPod ကို ပံ့ပိုးပါ</string>
|
||||||
<string name="settings_upgrade_status_description">သင်၏ ပံ့ပိုးသူ အခြေအနေ။</string>
|
<string name="settings_upgrade_status_description">သင်၏ ပံ့ပိုးသူ အခြေအနေ။</string>
|
||||||
<string name="upgrade_screen_why_title">အဆင့်မြှင့်တင်မှု အကျိုးအကျေးမများ</string>
|
<string name="upgrade_screen_why_title">အဆင့်မြှင့်တင်မှု အကျိုးအကျေးမများ</string>
|
||||||
<string name="upgrade_screen_how_title">ကူညီနည်းလမ်း</string>
|
<string name="upgrade_screen_how_title">ကူညီနည်းလမ်း</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Doner</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Jeg har allerede donert</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Jeg bruker alle pengene mine på AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS er gratis og åpen kildekode. Hvis du synes den er nyttig, kan du vurdere å sponse utviklingen for å bidra til at prosjektet går videre.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS er gratis og åpen kildekode. Hvis du synes den er nyttig, kan du vurdere å sponse utviklingen for å bidra til at prosjektet går videre.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Støtt utviklingen</string>
|
<string name="upgrade_foss_sponsor_action">Støtt utviklingen</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Ingen reklame. Ingen sporing. Ingen Google Play-avhengighet.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Ingen reklame. Ingen sporing. Ingen Google Play-avhengighet.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Støttespiller siden %s</string>
|
<string name="upgrade_foss_supporter_since">Støttespiller siden %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Takk for at du støtter utviklingen av CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Takk for at du støtter utviklingen av CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Åpne sponsorside</string>
|
<string name="upgrade_foss_sponsor_again_action">Åpne sponsorside</string>
|
||||||
<string name="settings_upgrade_status_label">Støtt CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Støtt CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Din status som støtter.</string>
|
<string name="settings_upgrade_status_description">Din status som støtter.</string>
|
||||||
<string name="upgrade_screen_why_title">Oppgraderingsfordeler</string>
|
<string name="upgrade_screen_why_title">Oppgraderingsfordeler</string>
|
||||||
<string name="upgrade_screen_how_title">Hvordan hjelpe</string>
|
<string name="upgrade_screen_how_title">Hvordan hjelpe</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">दान गर्नुहोस्</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">मैले पहिले नै दान गरिसकेको छु</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">म आफ्नो सबै पैसा AirPods मा खर्च गर्छु</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS निःशुल्क र खुला स्रोत छ। यदि तपाईंले उपयोगी पाउनुभएको छ भने, प्राजेक्ट चलाउन राख्न विकासमा प्रायोजन गर्न विचार गर्नुहोस्।</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS निःशुल्क र खुला स्रोत छ। यदि तपाईंले उपयोगी पाउनुभएको छ भने, प्राजेक्ट चलाउन राख्न विकासमा प्रायोजन गर्न विचार गर्नुहोस्।</string>
|
||||||
<string name="upgrade_foss_sponsor_action">विकासलाई प्रायोजन गर्नुहोस्</string>
|
<string name="upgrade_foss_sponsor_action">विकासलाई प्रायोजन गर्नुहोस्</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">कुनै विज्ञापन छैन। कुनै ट्रैकिङ छैन। Google Playमा बाँधिएको छैन।</string>
|
<string name="upgrade_foss_sponsor_subtitle">कुनै विज्ञापन छैन। कुनै ट्रैकिङ छैन। Google Playमा बाँधिएको छैन।</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">%s देखि समर्थक</string>
|
<string name="upgrade_foss_supporter_since">%s देखि समर्थक</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">CAPod को विकासलाई समर्थन गर्नुभएकोमा धन्यवाद!</string>
|
<string name="upgrade_foss_supporter_thanks">CAPod को विकासलाई समर्थन गर्नुभएकोमा धन्यवाद!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">प्रायोजक पृष्ठ खोल्नुहोस्</string>
|
<string name="upgrade_foss_sponsor_again_action">प्रायोजक पृष्ठ खोल्नुहोस्</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod को प्रायोजन गर्नुहोस्</string>
|
<string name="upgrade_foss_sponsor_label">CAPod को प्रायोजन गर्नुहोस्</string>
|
||||||
<string name="settings_upgrade_status_description">आफ्नो समर्थक स्थिति।</string>
|
<string name="settings_upgrade_status_description">आफ्नो समर्थक स्थिति।</string>
|
||||||
<string name="upgrade_screen_why_title">अपग्रेड लाभहरु</string>
|
<string name="upgrade_screen_why_title">अपग्रेड लाभहरु</string>
|
||||||
<string name="upgrade_screen_how_title">कसरी मद्दत गर्ने</string>
|
<string name="upgrade_screen_how_title">कसरी मद्दत गर्ने</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Doneren</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Ik heb al gedoneerd</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Ik besteed al mijn geld aan AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS is gratis en open source. Als je het nuttig vindt, overweeg dan om de ontwikkeling te sponsoren om het project gaande te houden.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS is gratis en open source. Als je het nuttig vindt, overweeg dan om de ontwikkeling te sponsoren om het project gaande te houden.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Sponsor ontwikkeling</string>
|
<string name="upgrade_foss_sponsor_action">Sponsor ontwikkeling</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Geen advertenties. Geen tracking. Geen Google Play-vergrendeling.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Geen advertenties. Geen tracking. Geen Google Play-vergrendeling.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Supporter sinds %s</string>
|
<string name="upgrade_foss_supporter_since">Supporter sinds %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Bedankt voor je steun aan de ontwikkeling van CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Bedankt voor je steun aan de ontwikkeling van CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Open de sponsorpagina</string>
|
<string name="upgrade_foss_sponsor_again_action">Open de sponsorpagina</string>
|
||||||
<string name="settings_upgrade_status_label">Sponsor CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Sponsor CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Je ondersteunersstatus.</string>
|
<string name="settings_upgrade_status_description">Je ondersteunersstatus.</string>
|
||||||
<string name="upgrade_screen_why_title">Voordelen van de upgrade</string>
|
<string name="upgrade_screen_why_title">Voordelen van de upgrade</string>
|
||||||
<string name="upgrade_screen_how_title">Hoe kun je helpen</string>
|
<string name="upgrade_screen_how_title">Hoe kun je helpen</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Wesprzyj</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Już wsparłem</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Wydałem wszystkie pieniądze na AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod Foss jest bezpłatny i otwarto-źródłowy. Jeśli uważasz go za użyteczny, rozważ sponsorowanie rozwoju, aby pomóc kontynuować projekt.</string>
|
<string name="upgrade_foss_preamble">CAPod Foss jest bezpłatny i otwarto-źródłowy. Jeśli uważasz go za użyteczny, rozważ sponsorowanie rozwoju, aby pomóc kontynuować projekt.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Wesprzyj rozwój</string>
|
<string name="upgrade_foss_sponsor_action">Wesprzyj rozwój</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Bez reklam. Bez śledzenia. Bez uzależnienia od Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Bez reklam. Bez śledzenia. Bez uzależnienia od Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Wspierający od %s</string>
|
<string name="upgrade_foss_supporter_since">Wspierający od %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Dziękuję za wsparcie rozwoju CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Dziękuję za wsparcie rozwoju CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Otwórz stronę wspierającego</string>
|
<string name="upgrade_foss_sponsor_again_action">Otwórz stronę wspierającego</string>
|
||||||
<string name="settings_upgrade_status_label">Sponsoruj CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Sponsoruj CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Status twojego wsparcia.</string>
|
<string name="settings_upgrade_status_description">Status twojego wsparcia.</string>
|
||||||
<string name="upgrade_screen_why_title">Korzyści z uaktualnienia</string>
|
<string name="upgrade_screen_why_title">Korzyści z uaktualnienia</string>
|
||||||
<string name="upgrade_screen_how_title">Jak pomóc</string>
|
<string name="upgrade_screen_how_title">Jak pomóc</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Doar</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Eu já doei</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Eu gasto todo o meu dinheiro em AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">O CAPod FOSS é gratuito e de código aberto. Se você o achar útil, considere patrocinar o desenvolvimento para ajudar a manter o projeto ativo.</string>
|
<string name="upgrade_foss_preamble">O CAPod FOSS é gratuito e de código aberto. Se você o achar útil, considere patrocinar o desenvolvimento para ajudar a manter o projeto ativo.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Patrocinador do desenvolvimento</string>
|
<string name="upgrade_foss_sponsor_action">Patrocinador do desenvolvimento</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Sem anúncios. Sem rastreamento. Sem dependência do Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Sem anúncios. Sem rastreamento. Sem dependência do Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Apoiador desde %s</string>
|
<string name="upgrade_foss_supporter_since">Apoiador desde %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Obrigado por apoiar o desenvolvimento do CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Obrigado por apoiar o desenvolvimento do CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Abrir página de patrocínio</string>
|
<string name="upgrade_foss_sponsor_again_action">Abrir página de patrocínio</string>
|
||||||
<string name="settings_upgrade_status_label">Patrocine o CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Patrocine o CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Seu status de apoiador.</string>
|
<string name="settings_upgrade_status_description">Seu status de apoiador.</string>
|
||||||
<string name="upgrade_screen_why_title">Benefícios da atualização</string>
|
<string name="upgrade_screen_why_title">Benefícios da atualização</string>
|
||||||
<string name="upgrade_screen_how_title">Como ajudar</string>
|
<string name="upgrade_screen_how_title">Como ajudar</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Doar</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Já doei</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Gastei todo o meu dinheiro em AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">O CAPod FOSS é gratuito e de código aberto. Se o achar útil, considere patrocinar o desenvolvimento para ajudar a manter o projeto ativo.</string>
|
<string name="upgrade_foss_preamble">O CAPod FOSS é gratuito e de código aberto. Se o achar útil, considere patrocinar o desenvolvimento para ajudar a manter o projeto ativo.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Patrocine o desenvolvimento</string>
|
<string name="upgrade_foss_sponsor_action">Patrocine o desenvolvimento</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Sem anúncios. Sem rastreamento. Sem dependência do Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Sem anúncios. Sem rastreamento. Sem dependência do Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Apoiante desde %s</string>
|
<string name="upgrade_foss_supporter_since">Apoiante desde %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Obrigado por apoiares o desenvolvimento do CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Obrigado por apoiares o desenvolvimento do CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Abrir página de patrocínio</string>
|
<string name="upgrade_foss_sponsor_again_action">Abrir página de patrocínio</string>
|
||||||
<string name="settings_upgrade_status_label">Apoie o CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Apoie o CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">O seu estado de apoiante.</string>
|
<string name="settings_upgrade_status_description">O seu estado de apoiante.</string>
|
||||||
<string name="upgrade_screen_why_title">Benefícios da atualização</string>
|
<string name="upgrade_screen_why_title">Benefícios da atualização</string>
|
||||||
<string name="upgrade_screen_how_title">Como ajudar</string>
|
<string name="upgrade_screen_how_title">Como ajudar</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Donar</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Hai gia donat</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Mett tut mes daners en AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS è gratuit ed open source. Sche ti chattast ch\'el è util, considerescha da sponsurisar il sviluppament per agidà a mantegnair il project.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS è gratuit ed open source. Sche ti chattast ch\'el è util, considerescha da sponsurisar il sviluppament per agidà a mantegnair il project.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Sponsurisar il sviluppament</string>
|
<string name="upgrade_foss_sponsor_action">Sponsurisar il sviluppament</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Nagins annunzis. Nagin tracking. Nagin blocadi da Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Nagins annunzis. Nagin tracking. Nagin blocadi da Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Sustegnider dapi %s</string>
|
<string name="upgrade_foss_supporter_since">Sustegnider dapi %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Grazia per sustegnair il svilup da CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Grazia per sustegnair il svilup da CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Avrir la pagina da sponsurisaziun</string>
|
<string name="upgrade_foss_sponsor_again_action">Avrir la pagina da sponsurisaziun</string>
|
||||||
<string name="settings_upgrade_status_label">Sponsurar CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Sponsurar CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Tes status da supporter.</string>
|
<string name="settings_upgrade_status_description">Tes status da supporter.</string>
|
||||||
<string name="upgrade_screen_why_title">Bials da l\'upgrade</string>
|
<string name="upgrade_screen_why_title">Bials da l\'upgrade</string>
|
||||||
<string name="upgrade_screen_how_title">Sco gidar</string>
|
<string name="upgrade_screen_how_title">Sco gidar</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Donează</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Am donat deja</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Mi-am cheltuit toți banii pe AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS este gratuit si open source. Daca il gasiti util, luati in considerare sponsorizarea dezvoltarii pentru a ajuta la continuarea proiectului.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS este gratuit si open source. Daca il gasiti util, luati in considerare sponsorizarea dezvoltarii pentru a ajuta la continuarea proiectului.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Sponsorizează dezvoltarea</string>
|
<string name="upgrade_foss_sponsor_action">Sponsorizează dezvoltarea</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Fara reclame. Fara urmarire. Fara dependenta de Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Fara reclame. Fara urmarire. Fara dependenta de Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Susținător din %s</string>
|
<string name="upgrade_foss_supporter_since">Susținător din %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Mulțumim că sprijini dezvoltarea CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Mulțumim că sprijini dezvoltarea CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Deschide pagina de sponsorizare</string>
|
<string name="upgrade_foss_sponsor_again_action">Deschide pagina de sponsorizare</string>
|
||||||
<string name="settings_upgrade_status_label">Sponsorizează CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Sponsorizează CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Statusul tău de susținător.</string>
|
<string name="settings_upgrade_status_description">Statusul tău de susținător.</string>
|
||||||
<string name="upgrade_screen_why_title">Beneficiile upgrade-ului</string>
|
<string name="upgrade_screen_why_title">Beneficiile upgrade-ului</string>
|
||||||
<string name="upgrade_screen_how_title">Cum să ajuți</string>
|
<string name="upgrade_screen_how_title">Cum să ajuți</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Пожертвовать</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Я уже пожертвовал</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Я потратил все свои деньги на AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS бесплатный и с открытым исходным кодом. Если Вам полезно приложение, рассмотрите возможность спонсировать разработку, чтобы помочь проекту продолжать развиваться.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS бесплатный и с открытым исходным кодом. Если Вам полезно приложение, рассмотрите возможность спонсировать разработку, чтобы помочь проекту продолжать развиваться.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Поддержать разработку</string>
|
<string name="upgrade_foss_sponsor_action">Поддержать разработку</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Без рекламы. Без слежки. Без привязки к Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Без рекламы. Без слежки. Без привязки к Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Спонсор с %s</string>
|
<string name="upgrade_foss_supporter_since">Спонсор с %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Спасибо за поддержку разработки CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Спасибо за поддержку разработки CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Открыть страницу спонсорства</string>
|
<string name="upgrade_foss_sponsor_again_action">Открыть страницу спонсорства</string>
|
||||||
<string name="settings_upgrade_status_label">Поддержать CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Поддержать CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Статус Вашей поддержки.</string>
|
<string name="settings_upgrade_status_description">Статус Вашей поддержки.</string>
|
||||||
<string name="upgrade_screen_why_title">Преимущества обновления</string>
|
<string name="upgrade_screen_why_title">Преимущества обновления</string>
|
||||||
<string name="upgrade_screen_how_title">Как помочь</string>
|
<string name="upgrade_screen_how_title">Как помочь</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Dona</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Apo giai donadu</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Apo spèndidu totu is soddos meos pro is AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS est gratis e fonte aberta. Si t’est de agiudu, considera de patrotzinare su isviluppu pro agiudare a mantennere su progetu.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS est gratis e fonte aberta. Si t’est de agiudu, considera de patrotzinare su isviluppu pro agiudare a mantennere su progetu.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Sponsoriza s\'isvilupu</string>
|
<string name="upgrade_foss_sponsor_action">Sponsoriza s\'isvilupu</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Peroe publicidade. Peroe trachiamentu. Peroe dipendentzia de Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Peroe publicidade. Peroe trachiamentu. Peroe dipendentzia de Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Sustentadore dae su %s</string>
|
<string name="upgrade_foss_supporter_since">Sustentadore dae su %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Gràtzias pro sustènnere s\'isvilupu de CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Gràtzias pro sustènnere s\'isvilupu de CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Aberi sa pàgina de sponsorizatzione</string>
|
<string name="upgrade_foss_sponsor_again_action">Aberi sa pàgina de sponsorizatzione</string>
|
||||||
<string name="settings_upgrade_status_label">Sostene CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Sostene CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">S\'istadu tuo de sustentadore.</string>
|
<string name="settings_upgrade_status_description">S\'istadu tuo de sustentadore.</string>
|
||||||
<string name="upgrade_screen_why_title">Benefitzios de s\'agiornamentu</string>
|
<string name="upgrade_screen_why_title">Benefitzios de s\'agiornamentu</string>
|
||||||
<string name="upgrade_screen_how_title">Comente agiudare</string>
|
<string name="upgrade_screen_how_title">Comente agiudare</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">පරිත්යාග</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">මම දැනටමත් පරිත්යාග කර ඇත</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">මම මගේ මුදල් සියල්ල AirPods සඳහා වියදම් කරමි</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS නියමිත සහ විවෘත මූලාශ්රයි. ඔබට ඉත උපකාරී නම්, ආයෝජනය ගිණුම් සහය ගෙවිපීම කිරීමට අර්වමයක් ගෙවිපීම් ප්රස්තා කරන්නට සංවර්ධන කරන්න.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS නියමිත සහ විවෘත මූලාශ්රයි. ඔබට ඉත උපකාරී නම්, ආයෝජනය ගිණුම් සහය ගෙවිපීම කිරීමට අර්වමයක් ගෙවිපීම් ප්රස්තා කරන්නට සංවර්ධන කරන්න.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">සංවර්ධනයට අනුග්රහය දෙන්න</string>
|
<string name="upgrade_foss_sponsor_action">සංවර්ධනයට අනුග්රහය දෙන්න</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">අළු නැත. ට්රැකිං නැත. Google Play සලකත්වය නැත.</string>
|
<string name="upgrade_foss_sponsor_subtitle">අළු නැත. ට්රැකිං නැත. Google Play සලකත්වය නැත.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">%s සිට අනුග්රාහකයෙකි</string>
|
<string name="upgrade_foss_supporter_since">%s සිට අනුග්රාහකයෙකි</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">CAPod හි සංවර්ධනයට සහාය දැක්වූ ඔබට ස්තූතියි!</string>
|
<string name="upgrade_foss_supporter_thanks">CAPod හි සංවර්ධනයට සහාය දැක්වූ ඔබට ස්තූතියි!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">අනුග්රාහක පිටුව විවෘත කරන්න</string>
|
<string name="upgrade_foss_sponsor_again_action">අනුග්රාහක පිටුව විවෘත කරන්න</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod සඳහා අනුග්රහක්</string>
|
<string name="upgrade_foss_sponsor_label">CAPod සඳහා අනුග්රහක්</string>
|
||||||
<string name="settings_upgrade_status_description">ඔබේ සහයෝගිතා තත්වය.</string>
|
<string name="settings_upgrade_status_description">ඔබේ සහයෝගිතා තත්වය.</string>
|
||||||
<string name="upgrade_screen_why_title">උඩ්ග්රේඩ් ප්රතිලාභ</string>
|
<string name="upgrade_screen_why_title">උඩ්ග්රේඩ් ප්රතිලාභ</string>
|
||||||
<string name="upgrade_screen_how_title">උදව් කරන්නේ කෙසේද</string>
|
<string name="upgrade_screen_how_title">උදව් කරන්නේ කෙසේද</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Prispieť</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Už som prispel/a</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Všetky peniaze som minul na AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS je zadarmo a open source. Ak ho nájdete užitočným, zvažte sponzorovanie vývoja, aby ste pomohli udržiavať projekt v chode.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS je zadarmo a open source. Ak ho nájdete užitočným, zvažte sponzorovanie vývoja, aby ste pomohli udržiavať projekt v chode.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Sponzorovaný vývoj</string>
|
<string name="upgrade_foss_sponsor_action">Sponzorovaný vývoj</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Žiadne reklamy. Žiadne sledovanie. Žiadna závislosť od Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Žiadne reklamy. Žiadne sledovanie. Žiadna závislosť od Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Podporovateľ od %s</string>
|
<string name="upgrade_foss_supporter_since">Podporovateľ od %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Ďakujeme, že podporujete vývoj CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Ďakujeme, že podporujete vývoj CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Otvoriť stránku sponzorstva</string>
|
<string name="upgrade_foss_sponsor_again_action">Otvoriť stránku sponzorstva</string>
|
||||||
<string name="settings_upgrade_status_label">Podporiť CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Podporiť CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Váš status podporovateľa.</string>
|
<string name="settings_upgrade_status_description">Váš status podporovateľa.</string>
|
||||||
<string name="upgrade_screen_why_title">Výhody upgradu</string>
|
<string name="upgrade_screen_why_title">Výhody upgradu</string>
|
||||||
<string name="upgrade_screen_how_title">Ako pomôcť</string>
|
<string name="upgrade_screen_how_title">Ako pomôcť</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Doniraj</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Sem že doniral</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Ves svoj denar porabim za AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS je brezplačen in odprtokoden. Če se vam zdi koristen, razmislite o sponzoriranju razvoja, da pomagate ohranjati projekt.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS je brezplačen in odprtokoden. Če se vam zdi koristen, razmislite o sponzoriranju razvoja, da pomagate ohranjati projekt.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Podpri razvoj</string>
|
<string name="upgrade_foss_sponsor_action">Podpri razvoj</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Brez oglasov. Brez sledenja. Brez vezave na Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Brez oglasov. Brez sledenja. Brez vezave na Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Podpornik od %s</string>
|
<string name="upgrade_foss_supporter_since">Podpornik od %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Hvala, ker podpirate razvoj CAPod-a!</string>
|
<string name="upgrade_foss_supporter_thanks">Hvala, ker podpirate razvoj CAPod-a!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Odpri stran za sponzorstvo</string>
|
<string name="upgrade_foss_sponsor_again_action">Odpri stran za sponzorstvo</string>
|
||||||
<string name="settings_upgrade_status_label">Podpri CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Podpri CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Tvoj status podpornika.</string>
|
<string name="settings_upgrade_status_description">Tvoj status podpornika.</string>
|
||||||
<string name="upgrade_screen_why_title">Prednosti nadgradnje</string>
|
<string name="upgrade_screen_why_title">Prednosti nadgradnje</string>
|
||||||
<string name="upgrade_screen_how_title">Kako pomagati.</string>
|
<string name="upgrade_screen_how_title">Kako pomagati.</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Dhuro</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Unë tashmë kam dhuruar</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Unë i shpenzoj të gjitha paratë e mia për AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS është falas dhe me burim të hapur. Nëse e gjeni të dobishmëm, konsideroni sponsorizimin e zhvillimit për ta mbajtur projektin gjallë.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS është falas dhe me burim të hapur. Nëse e gjeni të dobishmëm, konsideroni sponsorizimin e zhvillimit për ta mbajtur projektin gjallë.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Zhvillimi i sponsorëve</string>
|
<string name="upgrade_foss_sponsor_action">Zhvillimi i sponsorëve</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Pa reklama. Pa gjurmim. Pa varësi nga Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Pa reklama. Pa gjurmim. Pa varësi nga Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Mbështetës që nga %s</string>
|
<string name="upgrade_foss_supporter_since">Mbështetës që nga %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Faleminderit për mbështetjen e zhvillimit të CAPod-it!</string>
|
<string name="upgrade_foss_supporter_thanks">Faleminderit për mbështetjen e zhvillimit të CAPod-it!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Hap faqen e sponsorizimit</string>
|
<string name="upgrade_foss_sponsor_again_action">Hap faqen e sponsorizimit</string>
|
||||||
<string name="settings_upgrade_status_label">Mbështesni CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Mbështesni CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Statusi juaj si mbështetës.</string>
|
<string name="settings_upgrade_status_description">Statusi juaj si mbështetës.</string>
|
||||||
<string name="upgrade_screen_why_title">Përfitime të përmirësimit</string>
|
<string name="upgrade_screen_why_title">Përfitime të përmirësimit</string>
|
||||||
<string name="upgrade_screen_how_title">Si të ndihmoj</string>
|
<string name="upgrade_screen_how_title">Si të ndihmoj</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Донације</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Већ сам донирао/ла</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Сав новац трошим на АирПодс</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS је бесплатан и отвореног кода. Ако вам је користан, размотрите спонзорисање развоја да би пројекат остао жив.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS је бесплатан и отвореног кода. Ако вам је користан, размотрите спонзорисање развоја да би пројекат остао жив.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Спонзориши развој</string>
|
<string name="upgrade_foss_sponsor_action">Спонзориши развој</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Без реклама. Без праћења. Без зависности од Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Без реклама. Без праћења. Без зависности од Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Подржавалац од %s</string>
|
<string name="upgrade_foss_supporter_since">Подржавалац од %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Хвала вам што подржавате развој CAPod-а!</string>
|
<string name="upgrade_foss_supporter_thanks">Хвала вам што подржавате развој CAPod-а!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Отворите страницу за спонзорство</string>
|
<string name="upgrade_foss_sponsor_again_action">Отворите страницу за спонзорство</string>
|
||||||
<string name="settings_upgrade_status_label">Подржите CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Подржите CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Статус вашег подржавања.</string>
|
<string name="settings_upgrade_status_description">Статус вашег подржавања.</string>
|
||||||
<string name="upgrade_screen_why_title">Предности надградње</string>
|
<string name="upgrade_screen_why_title">Предности надградње</string>
|
||||||
<string name="upgrade_screen_how_title">Како помоћи</string>
|
<string name="upgrade_screen_how_title">Како помоћи</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Donera</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Jag har redan donerat</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Jag spenderar alla mina pengar på AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS är gratis och öppen källkod. Om du tycker att det är användbart kan du överväga att sponsra utvecklingen för att hjälpa till att hålla projektet vid liv.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS är gratis och öppen källkod. Om du tycker att det är användbart kan du överväga att sponsra utvecklingen för att hjälpa till att hålla projektet vid liv.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Sponsra utvecklingen</string>
|
<string name="upgrade_foss_sponsor_action">Sponsra utvecklingen</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Inga annonser. Ingen spårning. Ingen bindning till Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Inga annonser. Ingen spårning. Ingen bindning till Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Supporter sedan %s</string>
|
<string name="upgrade_foss_supporter_since">Supporter sedan %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Tack för att du stödjer utvecklingen av CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Tack för att du stödjer utvecklingen av CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Öppna sponsorsidan</string>
|
<string name="upgrade_foss_sponsor_again_action">Öppna sponsorsidan</string>
|
||||||
<string name="settings_upgrade_status_label">Sponsra CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Sponsra CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Din supporterstatus.</string>
|
<string name="settings_upgrade_status_description">Din supporterstatus.</string>
|
||||||
<string name="upgrade_screen_why_title">Uppgraderingsfördelar</string>
|
<string name="upgrade_screen_why_title">Uppgraderingsfördelar</string>
|
||||||
<string name="upgrade_screen_how_title">Hur du kan hjälpa</string>
|
<string name="upgrade_screen_how_title">Hur du kan hjälpa</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Changia</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Nimeshachangia tayari</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Natumia pesa zangu zote kwenye AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS ni bure na chanzo huria. Ikiwa unaikuta ni muhimu, fikiria kuchangia maendeleo ili kusaidia mradi kuendelea.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS ni bure na chanzo huria. Ikiwa unaikuta ni muhimu, fikiria kuchangia maendeleo ili kusaidia mradi kuendelea.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Faidhi maendeleo</string>
|
<string name="upgrade_foss_sponsor_action">Faidhi maendeleo</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Hakuna matangazo. Hakuna ufuatiliaji. Hakuna kufungwa kwa Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Hakuna matangazo. Hakuna ufuatiliaji. Hakuna kufungwa kwa Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Msaidizi tangu %s</string>
|
<string name="upgrade_foss_supporter_since">Msaidizi tangu %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Asante kwa kuunga mkono maendeleo ya CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Asante kwa kuunga mkono maendeleo ya CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Fungua ukurasa wa udhamini</string>
|
<string name="upgrade_foss_sponsor_again_action">Fungua ukurasa wa udhamini</string>
|
||||||
<string name="settings_upgrade_status_label">Kuunga mkono CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Kuunga mkono CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Hali yako ya kuunga mkono.</string>
|
<string name="settings_upgrade_status_description">Hali yako ya kuunga mkono.</string>
|
||||||
<string name="upgrade_screen_why_title">Faida za kuboreshwa</string>
|
<string name="upgrade_screen_why_title">Faida za kuboreshwa</string>
|
||||||
<string name="upgrade_screen_how_title">Jinsi ya kusaidia</string>
|
<string name="upgrade_screen_how_title">Jinsi ya kusaidia</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">நன்கொடை</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">நான் ஏற்கனவே நன்கொடை அளித்துவிட்டேன்</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">எனது பணத்தை எல்லாம் ஏர்பாட்களில் செலவிடுகிறேன்</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS இலவசமாகவும் திறழ் மூலக்கோடும் உள்ளது. இது பயனுள்ளதாக கணித்தால், தொடர்பு பொறுத்துக்க அம்சத்தை நிச்சயிக்கவும்.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS இலவசமாகவும் திறழ் மூலக்கோடும் உள்ளது. இது பயனுள்ளதாக கணித்தால், தொடர்பு பொறுத்துக்க அம்சத்தை நிச்சயிக்கவும்.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">மேம்பாட்டை ஸ்பான்சர் செய்யுங்கள்</string>
|
<string name="upgrade_foss_sponsor_action">மேம்பாட்டை ஸ்பான்சர் செய்யுங்கள்</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">ஐவிளம்பரம் இல்லை. கண்காணிப்பு இல்லை. Google Play கட்டுப்பாட்டு இல்லை.</string>
|
<string name="upgrade_foss_sponsor_subtitle">ஐவிளம்பரம் இல்லை. கண்காணிப்பு இல்லை. Google Play கட்டுப்பாட்டு இல்லை.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">%s முதல் ஆதரவாளர்</string>
|
<string name="upgrade_foss_supporter_since">%s முதல் ஆதரவாளர்</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">CAPod-இன் மேம்பாட்டை ஆதரித்ததற்கு நன்றி!</string>
|
<string name="upgrade_foss_supporter_thanks">CAPod-இன் மேம்பாட்டை ஆதரித்ததற்கு நன்றி!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">ஸ்பான்சர் பக்கத்தைத் திற</string>
|
<string name="upgrade_foss_sponsor_again_action">ஸ்பான்சர் பக்கத்தைத் திற</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod ஐ ஆதரிக்கவும்</string>
|
<string name="upgrade_foss_sponsor_label">CAPod ஐ ஆதரிக்கவும்</string>
|
||||||
<string name="settings_upgrade_status_description">உங்கள் ஆதரவாளர் நிலை.</string>
|
<string name="settings_upgrade_status_description">உங்கள் ஆதரவாளர் நிலை.</string>
|
||||||
<string name="upgrade_screen_why_title">மேம்படுத்தல் நன்மைகள்</string>
|
<string name="upgrade_screen_why_title">மேம்படுத்தல் நன்மைகள்</string>
|
||||||
<string name="upgrade_screen_how_title">எப்படி உதவுவது</string>
|
<string name="upgrade_screen_how_title">எப்படி உதவுவது</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">విరాళం ఇవ్వండి</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">నేను ఇప్పటికే విరాళం ఇచ్చాను</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">నా డబ్బు అంతా ఎయిర్పాడ్స్కే ఖర్చు చేస్తాను</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS ఉచిత మరియు ముక్త మూలం. ఇది ఉపయోగకరంగా అనిపిస్తే, ప్రాజెక్ట్ కొనసాగించడానికి అభివృద్ధిని స్పాన్సర్ చేయబక్తా పరిగణించండి.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS ఉచిత మరియు ముక్త మూలం. ఇది ఉపయోగకరంగా అనిపిస్తే, ప్రాజెక్ట్ కొనసాగించడానికి అభివృద్ధిని స్పాన్సర్ చేయబక్తా పరిగణించండి.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">అభివృద్ధిని స్పాన్సర్ చేయండి</string>
|
<string name="upgrade_foss_sponsor_action">అభివృద్ధిని స్పాన్సర్ చేయండి</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">జాహీరాతులు లేవు. ట్రాకింగ్ లేదు. Google Play ఒక్కటికి పరిమితం కాదు.</string>
|
<string name="upgrade_foss_sponsor_subtitle">జాహీరాతులు లేవు. ట్రాకింగ్ లేదు. Google Play ఒక్కటికి పరిమితం కాదు.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">%s నుండి సపోర్టర్</string>
|
<string name="upgrade_foss_supporter_since">%s నుండి సపోర్టర్</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">CAPod అభివృద్ధికి మద్దతు ఇచ్చినందుకు ధన్యవాదాలు!</string>
|
<string name="upgrade_foss_supporter_thanks">CAPod అభివృద్ధికి మద్దతు ఇచ్చినందుకు ధన్యవాదాలు!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">స్పాన్సర్ పేజీని తెరవండి</string>
|
<string name="upgrade_foss_sponsor_again_action">స్పాన్సర్ పేజీని తెరవండి</string>
|
||||||
<string name="settings_upgrade_status_label">CAPodకు స్పాన్సర్ చేయండి</string>
|
<string name="upgrade_foss_sponsor_label">CAPodకు స్పాన్సర్ చేయండి</string>
|
||||||
<string name="settings_upgrade_status_description">మీ సపోర్టర్ స్థితి.</string>
|
<string name="settings_upgrade_status_description">మీ సపోర్టర్ స్థితి.</string>
|
||||||
<string name="upgrade_screen_why_title">అప్గ్రేడ్ ప్రయోజనాలు</string>
|
<string name="upgrade_screen_why_title">అప్గ్రేడ్ ప్రయోజనాలు</string>
|
||||||
<string name="upgrade_screen_how_title">ఎలా సహాయం చేయాలి</string>
|
<string name="upgrade_screen_how_title">ఎలా సహాయం చేయాలి</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">บริจาค</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">ฉันบริจาคแล้ว</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">ฉันใช้เงินทั้งหมดไปกับ AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS เป็นฟรีและโอเพนซอร์ส หากคุณเห็นว่ามีประโยชน์ ลองสนับสนุนการพัฒนาเพื่อช่วยให้โครงการดำเนินต่อไป</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS เป็นฟรีและโอเพนซอร์ส หากคุณเห็นว่ามีประโยชน์ ลองสนับสนุนการพัฒนาเพื่อช่วยให้โครงการดำเนินต่อไป</string>
|
||||||
<string name="upgrade_foss_sponsor_action">สปอนเซอร์การพัฒนา</string>
|
<string name="upgrade_foss_sponsor_action">สปอนเซอร์การพัฒนา</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">ไม่มีโฆษณา ไม่ติดตาม ไม่ผูกขาด Google Play</string>
|
<string name="upgrade_foss_sponsor_subtitle">ไม่มีโฆษณา ไม่ติดตาม ไม่ผูกขาด Google Play</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">ผู้สนับสนุนตั้งแต่ %s</string>
|
<string name="upgrade_foss_supporter_since">ผู้สนับสนุนตั้งแต่ %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">ขอบคุณที่สนับสนุนการพัฒนา CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">ขอบคุณที่สนับสนุนการพัฒนา CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">เปิดหน้าสนับสนุน</string>
|
<string name="upgrade_foss_sponsor_again_action">เปิดหน้าสนับสนุน</string>
|
||||||
<string name="settings_upgrade_status_label">สนับสนุน CAPod</string>
|
<string name="upgrade_foss_sponsor_label">สนับสนุน CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">สถานะผู้สนับสนุนของคุณ</string>
|
<string name="settings_upgrade_status_description">สถานะผู้สนับสนุนของคุณ</string>
|
||||||
<string name="upgrade_screen_why_title">ประโยชน์ของการอัปเกรด</string>
|
<string name="upgrade_screen_why_title">ประโยชน์ของการอัปเกรด</string>
|
||||||
<string name="upgrade_screen_how_title">วิธีการช่วยเหลือ</string>
|
<string name="upgrade_screen_how_title">วิธีการช่วยเหลือ</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Bağış yap</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Zaten bağış yaptım</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Tüm paramı AirPods\'a harcıyorum</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS ücretsiz ve açık kaynaklıdır. Eğer faydalı bulduysan, projenin devam edebilmesi için lütfen geliştirmeye destek olmayı düşün.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS ücretsiz ve açık kaynaklıdır. Eğer faydalı bulduysan, projenin devam edebilmesi için lütfen geliştirmeye destek olmayı düşün.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Geliştirmeyi destekleyin</string>
|
<string name="upgrade_foss_sponsor_action">Geliştirmeyi destekleyin</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Reklam yok. Takip yok. Google Play sınırlaması yok.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Reklam yok. Takip yok. Google Play sınırlaması yok.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">%s tarihinden beri destekçi</string>
|
<string name="upgrade_foss_supporter_since">%s tarihinden beri destekçi</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">CAPod\'un geliştirilmesini desteklediğin için teşekkürler!</string>
|
<string name="upgrade_foss_supporter_thanks">CAPod\'un geliştirilmesini desteklediğin için teşekkürler!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Sponsor sayfasını aç</string>
|
<string name="upgrade_foss_sponsor_again_action">Sponsor sayfasını aç</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod\'u destekle</string>
|
<string name="upgrade_foss_sponsor_label">CAPod\'u destekle</string>
|
||||||
<string name="settings_upgrade_status_description">Destekçi durumun.</string>
|
<string name="settings_upgrade_status_description">Destekçi durumun.</string>
|
||||||
<string name="upgrade_screen_why_title">Yükseltme Avantajları</string>
|
<string name="upgrade_screen_why_title">Yükseltme Avantajları</string>
|
||||||
<string name="upgrade_screen_how_title">Nasıl yardım edilir</string>
|
<string name="upgrade_screen_how_title">Nasıl yardım edilir</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Пожертва</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Вже пожертвував</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Витратив усі гроші на AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS є безкоштовним та відкритим програмним забезпеченням. Якщо він вам корисний, розгляньте можливість спонсорування розробки, щоб допомогти проєкту продовжувати роботу.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS є безкоштовним та відкритим програмним забезпеченням. Якщо він вам корисний, розгляньте можливість спонсорування розробки, щоб допомогти проєкту продовжувати роботу.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Розвиток спонсорів</string>
|
<string name="upgrade_foss_sponsor_action">Розвиток спонсорів</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Без реклами. Без стеження. Без прив\'язки до Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Без реклами. Без стеження. Без прив\'язки до Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Підтримує з %s</string>
|
<string name="upgrade_foss_supporter_since">Підтримує з %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Дякуємо за підтримку розробки CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Дякуємо за підтримку розробки CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Відкрити сторінку спонсорства</string>
|
<string name="upgrade_foss_sponsor_again_action">Відкрити сторінку спонсорства</string>
|
||||||
<string name="settings_upgrade_status_label">Спонсорувати CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Спонсорувати CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Ваш статус прихильника.</string>
|
<string name="settings_upgrade_status_description">Ваш статус прихильника.</string>
|
||||||
<string name="upgrade_screen_why_title">Переваги оновлення</string>
|
<string name="upgrade_screen_why_title">Переваги оновлення</string>
|
||||||
<string name="upgrade_screen_how_title">Як допомогти</string>
|
<string name="upgrade_screen_how_title">Як допомогти</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">عطیہ کریں۔</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">میں نے پہلے ہی عطیہ کر دیا ہے۔</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">میں اپنی تمام رقم ایئر پوڈز پر خرچ کرتا ہوں۔</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS مفت اور اوپن سورس ہے۔ اگر آپ اسے مفید پاتے ہیں، تو منصوبے کو سپانسر کرنے کا خیال کریں تاکہ پراجیکٹ جاری رہے۔</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS مفت اور اوپن سورس ہے۔ اگر آپ اسے مفید پاتے ہیں، تو منصوبے کو سپانسر کرنے کا خیال کریں تاکہ پراجیکٹ جاری رہے۔</string>
|
||||||
<string name="upgrade_foss_sponsor_action">ترقی کو اسپانسر کریں</string>
|
<string name="upgrade_foss_sponsor_action">ترقی کو اسپانسر کریں</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">کوئی اشتہار نہیں۔ کوئی ٹریکنگ نہیں۔ کوئی Google Play کی قید نہیں۔</string>
|
<string name="upgrade_foss_sponsor_subtitle">کوئی اشتہار نہیں۔ کوئی ٹریکنگ نہیں۔ کوئی Google Play کی قید نہیں۔</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">%s سے سپورٹر</string>
|
<string name="upgrade_foss_supporter_since">%s سے سپورٹر</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">CAPod کی ترقی کی حمایت کرنے کا شکریہ!</string>
|
<string name="upgrade_foss_supporter_thanks">CAPod کی ترقی کی حمایت کرنے کا شکریہ!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">سپانسر پیج کھولیں</string>
|
<string name="upgrade_foss_sponsor_again_action">سپانسر پیج کھولیں</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod کی سرپرستی کریں</string>
|
<string name="upgrade_foss_sponsor_label">CAPod کی سرپرستی کریں</string>
|
||||||
<string name="settings_upgrade_status_description">آپ کی حامی حالت۔</string>
|
<string name="settings_upgrade_status_description">آپ کی حامی حالت۔</string>
|
||||||
<string name="upgrade_screen_why_title">اپ گریڈ کے فوائد</string>
|
<string name="upgrade_screen_why_title">اپ گریڈ کے فوائد</string>
|
||||||
<string name="upgrade_screen_how_title">کیسے مدد کریں</string>
|
<string name="upgrade_screen_how_title">کیسے مدد کریں</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Xayriya qilish</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Men allaqachon xayriya qildim</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Men butun pulimni AirPods uchun sarflayman</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS bepul va ochiq manbali. Agar foydali deb topsangiz, loyihani davom ettirishga yordam berish uchun rivojlantiruvchini qo\'llab-quvvatlashni ko\'rib chiqing.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS bepul va ochiq manbali. Agar foydali deb topsangiz, loyihani davom ettirishga yordam berish uchun rivojlantiruvchini qo\'llab-quvvatlashni ko\'rib chiqing.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Rivojlanishni sponsorlik qilish</string>
|
<string name="upgrade_foss_sponsor_action">Rivojlanishni sponsorlik qilish</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Reklamasiz. Kuzatishsiz. Google Play cheklovlarisiz.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Reklamasiz. Kuzatishsiz. Google Play cheklovlarisiz.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">%s dan beri homiy</string>
|
<string name="upgrade_foss_supporter_since">%s dan beri homiy</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">CAPod rivojlanishini qo\'llab-quvvatlaganingiz uchun rahmat!</string>
|
<string name="upgrade_foss_supporter_thanks">CAPod rivojlanishini qo\'llab-quvvatlaganingiz uchun rahmat!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Homiylik sahifasini ochish</string>
|
<string name="upgrade_foss_sponsor_again_action">Homiylik sahifasini ochish</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod ni homiylik qiling</string>
|
<string name="upgrade_foss_sponsor_label">CAPod ni homiylik qiling</string>
|
||||||
<string name="settings_upgrade_status_description">Sizning homiy holati.</string>
|
<string name="settings_upgrade_status_description">Sizning homiy holati.</string>
|
||||||
<string name="upgrade_screen_why_title">Yangilashning afzalliklari</string>
|
<string name="upgrade_screen_why_title">Yangilashning afzalliklari</string>
|
||||||
<string name="upgrade_screen_how_title">Qanday yordam berish</string>
|
<string name="upgrade_screen_how_title">Qanday yordam berish</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Quyên tặng</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Tôi đã quyên góp</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Tôi tiêu hết tiền cho AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS miễn phí và mã nguồn mở. Nếu bạn thấy nó hữu ích, hãy cân nhắc tài trợ cho việc phát triển để giúp duy trì dự án.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS miễn phí và mã nguồn mở. Nếu bạn thấy nó hữu ích, hãy cân nhắc tài trợ cho việc phát triển để giúp duy trì dự án.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Tài trợ nhà phát triển</string>
|
<string name="upgrade_foss_sponsor_action">Tài trợ nhà phát triển</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Không quảng cáo. Không theo dõi. Không phụ thuộc Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Không quảng cáo. Không theo dõi. Không phụ thuộc Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Người ủng hộ từ %s</string>
|
<string name="upgrade_foss_supporter_since">Người ủng hộ từ %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Cảm ơn bạn đã ủng hộ sự phát triển của CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Cảm ơn bạn đã ủng hộ sự phát triển của CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Mở trang tài trợ</string>
|
<string name="upgrade_foss_sponsor_again_action">Mở trang tài trợ</string>
|
||||||
<string name="settings_upgrade_status_label">Tài trợ cho CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Tài trợ cho CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Trạng thái nhà tài trợ của bạn.</string>
|
<string name="settings_upgrade_status_description">Trạng thái nhà tài trợ của bạn.</string>
|
||||||
<string name="upgrade_screen_why_title">Lợi ích nâng cấp</string>
|
<string name="upgrade_screen_why_title">Lợi ích nâng cấp</string>
|
||||||
<string name="upgrade_screen_how_title">Làm thế nào để giúp đỡ</string>
|
<string name="upgrade_screen_how_title">Làm thế nào để giúp đỡ</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">捐赠</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">已捐赠过了</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">钱都用来买 AirPods 了</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS 是免费开源的。如果您觉得它有用,请考虑赞助开发以帮助项目持续下去。</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS 是免费开源的。如果您觉得它有用,请考虑赞助开发以帮助项目持续下去。</string>
|
||||||
<string name="upgrade_foss_sponsor_action">赞助开发</string>
|
<string name="upgrade_foss_sponsor_action">赞助开发</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">无广告。无追踪。无 Google Play 绑定。</string>
|
<string name="upgrade_foss_sponsor_subtitle">无广告。无追踪。无 Google Play 绑定。</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">自 %s 起成为支持者</string>
|
<string name="upgrade_foss_supporter_since">自 %s 起成为支持者</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">感谢您支持 CAPod 的开发!</string>
|
<string name="upgrade_foss_supporter_thanks">感谢您支持 CAPod 的开发!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">打开赞助页面</string>
|
<string name="upgrade_foss_sponsor_again_action">打开赞助页面</string>
|
||||||
<string name="settings_upgrade_status_label">赞助 CAPod</string>
|
<string name="upgrade_foss_sponsor_label">赞助 CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">您的赞助者身份。</string>
|
<string name="settings_upgrade_status_description">您的赞助者身份。</string>
|
||||||
<string name="upgrade_screen_why_title">升级优势</string>
|
<string name="upgrade_screen_why_title">升级优势</string>
|
||||||
<string name="upgrade_screen_how_title">如何帮助我们</string>
|
<string name="upgrade_screen_how_title">如何帮助我们</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">資助</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">我已經資助了</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">我已經為 AirPods 傾家蕩產了</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS 是免費且開源的。如果您覺得它對您有幫助,請考慮贊助開發以支持項目繼續運行。</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS 是免費且開源的。如果您覺得它對您有幫助,請考慮贊助開發以支持項目繼續運行。</string>
|
||||||
<string name="upgrade_foss_sponsor_action">贊助開發</string>
|
<string name="upgrade_foss_sponsor_action">贊助開發</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">沒有廣告。沒有追蹤。沒有 Google Play 鎖定。</string>
|
<string name="upgrade_foss_sponsor_subtitle">沒有廣告。沒有追蹤。沒有 Google Play 鎖定。</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">自 %s 起成為贊助者</string>
|
<string name="upgrade_foss_supporter_since">自 %s 起成為贊助者</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">感謝你支持 CAPod 的開發!</string>
|
<string name="upgrade_foss_supporter_thanks">感謝你支持 CAPod 的開發!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">開啟贊助頁面</string>
|
<string name="upgrade_foss_sponsor_again_action">開啟贊助頁面</string>
|
||||||
<string name="settings_upgrade_status_label">贊助 CAPod</string>
|
<string name="upgrade_foss_sponsor_label">贊助 CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">您的贊助者身份。</string>
|
<string name="settings_upgrade_status_description">您的贊助者身份。</string>
|
||||||
<string name="upgrade_screen_why_title">升級優勢</string>
|
<string name="upgrade_screen_why_title">升級優勢</string>
|
||||||
<string name="upgrade_screen_how_title">如何協助</string>
|
<string name="upgrade_screen_how_title">如何協助</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">抖內</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">我已經抖內了</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">我已經為 AirPods 傾家蕩產了</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS 是免費且開源的。如果您覺得它對您有幫助,請考慮贊助開發以支持專案繼續運行。</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS 是免費且開源的。如果您覺得它對您有幫助,請考慮贊助開發以支持專案繼續運行。</string>
|
||||||
<string name="upgrade_foss_sponsor_action">贊助開發</string>
|
<string name="upgrade_foss_sponsor_action">贊助開發</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">無廣告。無追蹤。無 Google Play 鎖定。</string>
|
<string name="upgrade_foss_sponsor_subtitle">無廣告。無追蹤。無 Google Play 鎖定。</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">自 %s 起成為贊助者</string>
|
<string name="upgrade_foss_supporter_since">自 %s 起成為贊助者</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">感謝您支持 CAPod 的開發!</string>
|
<string name="upgrade_foss_supporter_thanks">感謝您支持 CAPod 的開發!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">開啟贊助頁面</string>
|
<string name="upgrade_foss_sponsor_again_action">開啟贊助頁面</string>
|
||||||
<string name="settings_upgrade_status_label">贊助 CAPod</string>
|
<string name="upgrade_foss_sponsor_label">贊助 CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">您的贊助狀態。</string>
|
<string name="settings_upgrade_status_description">您的贊助狀態。</string>
|
||||||
<string name="upgrade_screen_why_title">升級優勢</string>
|
<string name="upgrade_screen_why_title">升級優勢</string>
|
||||||
<string name="upgrade_screen_how_title">如何協助</string>
|
<string name="upgrade_screen_how_title">如何協助</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Nikela</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">Senginikele kakade</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">Ngisebenzisa yonke imali yami kuma-AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">I-CAPod FOSS imahhala futhi ivulelwe umphakathi. Uma uyithola iyasiza, cabanga ngokuxhasa ukuthuthukiswa ukuze usizo kugcina iphrojekthi iqhubeka.</string>
|
<string name="upgrade_foss_preamble">I-CAPod FOSS imahhala futhi ivulelwe umphakathi. Uma uyithola iyasiza, cabanga ngokuxhasa ukuthuthukiswa ukuze usizo kugcina iphrojekthi iqhubeka.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Xhasa ukuthuthukiswa</string>
|
<string name="upgrade_foss_sponsor_action">Xhasa ukuthuthukiswa</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">Azikho izibhangeli. Akunakulandelelwa. Ayikho ukuvinjwa kwe-Google Play.</string>
|
<string name="upgrade_foss_sponsor_subtitle">Azikho izibhangeli. Akunakulandelelwa. Ayikho ukuvinjwa kwe-Google Play.</string>
|
||||||
@@ -10,7 +7,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Umsekeli kusukela ngo-%s</string>
|
<string name="upgrade_foss_supporter_since">Umsekeli kusukela ngo-%s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Ngiyabonga ngokusekela ukuthuthukiswa kwe-CAPod!</string>
|
<string name="upgrade_foss_supporter_thanks">Ngiyabonga ngokusekela ukuthuthukiswa kwe-CAPod!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Vula ikhasi lomxhasi</string>
|
<string name="upgrade_foss_sponsor_again_action">Vula ikhasi lomxhasi</string>
|
||||||
<string name="settings_upgrade_status_label">Uxhasa i-CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Uxhasa i-CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Isimo sakho sokusekela.</string>
|
<string name="settings_upgrade_status_description">Isimo sakho sokusekela.</string>
|
||||||
<string name="upgrade_screen_why_title">Imikhulu yokuphucula</string>
|
<string name="upgrade_screen_why_title">Imikhulu yokuphucula</string>
|
||||||
<string name="upgrade_screen_how_title">Indlela yokusiza</string>
|
<string name="upgrade_screen_how_title">Indlela yokusiza</string>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="foss_upgrade_donate_label">Donate</string>
|
|
||||||
<string name="foss_upgrade_alreadydonated_label">I already donated</string>
|
|
||||||
<string name="foss_upgrade_no_money_label">I spend all my money on AirPods</string>
|
|
||||||
<string name="upgrade_foss_preamble">CAPod FOSS is free and open source. If you find it useful, consider sponsoring development to help keep the project going.</string>
|
<string name="upgrade_foss_preamble">CAPod FOSS is free and open source. If you find it useful, consider sponsoring development to help keep the project going.</string>
|
||||||
<string name="upgrade_foss_sponsor_action">Sponsor development</string>
|
<string name="upgrade_foss_sponsor_action">Sponsor development</string>
|
||||||
<string name="upgrade_foss_sponsor_subtitle">No ads. No tracking. No Google Play lock-in.</string>
|
<string name="upgrade_foss_sponsor_subtitle">No ads. No tracking. No Google Play lock-in.</string>
|
||||||
@@ -11,7 +8,7 @@
|
|||||||
<string name="upgrade_foss_supporter_since">Supporter since %s</string>
|
<string name="upgrade_foss_supporter_since">Supporter since %s</string>
|
||||||
<string name="upgrade_foss_supporter_thanks">Thank you for supporting CAPod\'s development!</string>
|
<string name="upgrade_foss_supporter_thanks">Thank you for supporting CAPod\'s development!</string>
|
||||||
<string name="upgrade_foss_sponsor_again_action">Open sponsor page</string>
|
<string name="upgrade_foss_sponsor_again_action">Open sponsor page</string>
|
||||||
<string name="settings_upgrade_status_label">Sponsor CAPod</string>
|
<string name="upgrade_foss_sponsor_label">Sponsor CAPod</string>
|
||||||
<string name="settings_upgrade_status_description">Your supporter status.</string>
|
<string name="settings_upgrade_status_description">Your supporter status.</string>
|
||||||
<string name="upgrade_screen_why_title">Upgrade benefits</string>
|
<string name="upgrade_screen_why_title">Upgrade benefits</string>
|
||||||
<string name="upgrade_screen_how_title">How to help</string>
|
<string name="upgrade_screen_how_title">How to help</string>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package eu.darken.capod.common.upgrade.core
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import com.android.billingclient.api.BillingClient.BillingResponseCode
|
import com.android.billingclient.api.BillingClient.BillingResponseCode
|
||||||
import com.android.billingclient.api.Purchase
|
|
||||||
import eu.darken.capod.common.coroutine.AppScope
|
import eu.darken.capod.common.coroutine.AppScope
|
||||||
import eu.darken.capod.common.datastore.value
|
import eu.darken.capod.common.datastore.value
|
||||||
import eu.darken.capod.common.debug.logging.Logging.Priority.ERROR
|
import eu.darken.capod.common.debug.logging.Logging.Priority.ERROR
|
||||||
@@ -18,11 +17,13 @@ import eu.darken.capod.common.upgrade.core.billing.BillingData
|
|||||||
import eu.darken.capod.common.upgrade.core.billing.BillingManager
|
import eu.darken.capod.common.upgrade.core.billing.BillingManager
|
||||||
import eu.darken.capod.common.upgrade.core.billing.GplayServiceUnavailableException
|
import eu.darken.capod.common.upgrade.core.billing.GplayServiceUnavailableException
|
||||||
import eu.darken.capod.common.upgrade.core.billing.ItemAlreadyOwnedBillingException
|
import eu.darken.capod.common.upgrade.core.billing.ItemAlreadyOwnedBillingException
|
||||||
|
import eu.darken.capod.common.upgrade.core.billing.PendingPurchaseBillingException
|
||||||
import eu.darken.capod.common.upgrade.core.billing.PurchasedSku
|
import eu.darken.capod.common.upgrade.core.billing.PurchasedSku
|
||||||
import eu.darken.capod.common.upgrade.core.billing.Sku
|
import eu.darken.capod.common.upgrade.core.billing.Sku
|
||||||
import eu.darken.capod.common.upgrade.core.billing.SkuDetails
|
import eu.darken.capod.common.upgrade.core.billing.SkuDetails
|
||||||
import eu.darken.capod.common.upgrade.core.billing.UserCanceledBillingException
|
import eu.darken.capod.common.upgrade.core.billing.UserCanceledBillingException
|
||||||
import eu.darken.capod.common.upgrade.core.billing.client.redacted
|
import eu.darken.capod.common.upgrade.core.billing.client.redacted
|
||||||
|
import eu.darken.capod.common.upgrade.core.billing.work.PurchaseAckScheduler
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Deferred
|
import kotlinx.coroutines.Deferred
|
||||||
@@ -58,6 +59,7 @@ class UpgradeRepoGplay @Inject constructor(
|
|||||||
private val billingManager: BillingManager,
|
private val billingManager: BillingManager,
|
||||||
private val billingCache: BillingCache,
|
private val billingCache: BillingCache,
|
||||||
private val curriculumVitae: CurriculumVitae,
|
private val curriculumVitae: CurriculumVitae,
|
||||||
|
private val ackScheduler: PurchaseAckScheduler,
|
||||||
) : UpgradeRepo {
|
) : UpgradeRepo {
|
||||||
|
|
||||||
override val storeSite: String = STORE_SITE
|
override val storeSite: String = STORE_SITE
|
||||||
@@ -137,6 +139,7 @@ class UpgradeRepoGplay @Inject constructor(
|
|||||||
.onEach { failedAt -> recordProUnconfirmed(failedAt) }
|
.onEach { failedAt -> recordProUnconfirmed(failedAt) }
|
||||||
.setupCommonEventHandlers(TAG) { "connectionFailureRecorder" }
|
.setupCommonEventHandlers(TAG) { "connectionFailureRecorder" }
|
||||||
.launchIn(scope)
|
.launchIn(scope)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Settledness travels WITH the ownership data (Info.isSettled), never on a parallel flow —
|
// Settledness travels WITH the ownership data (Info.isSettled), never on a parallel flow —
|
||||||
@@ -255,6 +258,18 @@ class UpgradeRepoGplay @Inject constructor(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
// Persistent ack safety net, launch trigger: armed and AWAITED before the Play sheet
|
||||||
|
// can open, so the WorkManager DB transaction lands even if the process dies around
|
||||||
|
// the sheet — the exact window behind Play's unacknowledged-purchase auto-refunds.
|
||||||
|
// Failure to arm never blocks the purchase; the foreground ack path still exists.
|
||||||
|
try {
|
||||||
|
ackScheduler.armForBillingFlowLaunch()
|
||||||
|
} catch (e: CancellationException) {
|
||||||
|
throw e
|
||||||
|
} catch (e: Exception) {
|
||||||
|
log(TAG, WARN) { "Failed to arm ack safety net for launch: ${e.asLog()}" }
|
||||||
|
}
|
||||||
|
|
||||||
// Bounded, like every other Play path (refresh, restore, SKU query, ack). useConnection
|
// Bounded, like every other Play path (refresh, restore, SKU query, ack). useConnection
|
||||||
// waits for a healthy connection indefinitely, so a Play outage between rendering the
|
// waits for a healthy connection indefinitely, so a Play outage between rendering the
|
||||||
// offers and this tap would park the launch forever — with launchBusySku still held,
|
// offers and this tap would park the launch forever — with launchBusySku still held,
|
||||||
@@ -284,9 +299,18 @@ class UpgradeRepoGplay @Inject constructor(
|
|||||||
// Reconciled only if the restore actually returned the SKU Play claims is
|
// Reconciled only if the restore actually returned the SKU Play claims is
|
||||||
// owned — a grace-only isPro doesn't count, the entitlement is still missing.
|
// owned — a grace-only isPro doesn't count, the entitlement is still missing.
|
||||||
if (restored?.upgrades?.any { it.sku == sku } != true) {
|
if (restored?.upgrades?.any { it.sku == sku } != true) {
|
||||||
// Couldn't reconcile the entitlement (pending purchase, account mismatch,
|
if (restored?.pendingSkus?.isNotEmpty() == true) {
|
||||||
// Play quirk) — fall back to the already-owned dialog with restore tips.
|
// Play blocks re-purchasing a product whose payment it is still
|
||||||
onError(e)
|
// processing. "Already owned" is technically what Play said, but the
|
||||||
|
// dialog's restore tips are the wrong advice: nothing to restore, and
|
||||||
|
// the entitlement lands by itself once the payment clears.
|
||||||
|
log(TAG, INFO) { "Already-owned recovery found a pending payment" }
|
||||||
|
onError(PendingPurchaseBillingException(e))
|
||||||
|
} else {
|
||||||
|
// Couldn't reconcile the entitlement (account mismatch, Play quirk) —
|
||||||
|
// fall back to the already-owned dialog with restore tips.
|
||||||
|
onError(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,12 +353,15 @@ class UpgradeRepoGplay @Inject constructor(
|
|||||||
|
|
||||||
suspend fun querySkus(vararg skus: Sku): Collection<SkuDetails> = billingManager.querySkus(*skus)
|
suspend fun querySkus(vararg skus: Sku): Collection<SkuDetails> = billingManager.querySkus(*skus)
|
||||||
|
|
||||||
// Strict subscription lookup for the pre-purchase gate: fresh SUBS-only query with explicit
|
// Strict purchase-state lookup for the pre-purchase gates: a fresh COMPLETE round-trip with
|
||||||
// failure. No grace substitution and no cross-product-type tolerance (unlike refresh() and
|
// explicit failure. No grace substitution and no partial tolerance (unlike refresh() and
|
||||||
// restorePurchaseNow()) — callers must treat any error as "couldn't verify" and fail closed.
|
// restorePurchaseNow()) — callers must treat any error as "couldn't verify" and fail closed.
|
||||||
suspend fun queryCurrentSubscriptions(): Collection<Purchase> {
|
// Covers both product types and pending payments, because both can make a purchase wrong: a
|
||||||
log(TAG) { "queryCurrentSubscriptions()" }
|
// renewing subscription (double billing) and a payment Play is still processing (Play rejects
|
||||||
return billingManager.querySubscriptions()
|
// the re-purchase).
|
||||||
|
suspend fun verifyPurchaseStateNow(): Info {
|
||||||
|
log(TAG) { "verifyPurchaseStateNow()" }
|
||||||
|
return Info(billingData = billingManager.refreshStrict(), isSettled = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun refresh() {
|
override suspend fun refresh() {
|
||||||
@@ -496,8 +523,8 @@ class UpgradeRepoGplay @Inject constructor(
|
|||||||
// Shared Pro/grace mapping used by both the reactive upgradeInfo flow and restorePurchaseNow().
|
// Shared Pro/grace mapping used by both the reactive upgradeInfo flow and restorePurchaseNow().
|
||||||
// Only relinquishes Pro if we haven't had it for a while (grace period). READ-ONLY: this runs on
|
// Only relinquishes Pro if we haven't had it for a while (grace period). READ-ONLY: this runs on
|
||||||
// replayed shared-flow data too, so it must never stamp the grace cache — see recordProState().
|
// replayed shared-flow data too, so it must never stamp the grace cache — see recordProState().
|
||||||
// settled comes from the caller, never from billingData nullness: the grace branch returns an
|
// settled comes from the caller, never from billingData nullness: a null-data Info can be
|
||||||
// Info with billingData = null that may well be settled (built from a real empty snapshot).
|
// perfectly settled (a real empty snapshot), and the grace branch carries data through anyway.
|
||||||
private suspend fun BillingData?.toUpgradeInfo(settled: Boolean): Info {
|
private suspend fun BillingData?.toUpgradeInfo(settled: Boolean): Info {
|
||||||
// Branch on MAPPED upgrades, not raw purchases: a purchase list containing only products
|
// Branch on MAPPED upgrades, not raw purchases: a purchase list containing only products
|
||||||
// this app doesn't know maps to zero upgrades and must fall through to the grace check —
|
// this app doesn't know maps to zero upgrades and must fall through to the grace check —
|
||||||
@@ -513,7 +540,11 @@ class UpgradeRepoGplay @Inject constructor(
|
|||||||
return when {
|
return when {
|
||||||
(now - lastProStateAt) < graceWindowMs() -> {
|
(now - lastProStateAt) < graceWindowMs() -> {
|
||||||
log(TAG, VERBOSE) { "We are not pro, but were recently, did GPlay try annoy us again?" }
|
log(TAG, VERBOSE) { "We are not pro, but were recently, did GPlay try annoy us again?" }
|
||||||
Info(gracePeriod = true, billingData = null, isSettled = settled)
|
// billingData is carried through, not dropped: this branch is only reached when the
|
||||||
|
// mapped upgrades are empty, so entitlement stays empty either way — but a pending
|
||||||
|
// payment must stay visible, and a grace user waiting on one is exactly who needs
|
||||||
|
// the explanation.
|
||||||
|
Info(gracePeriod = true, billingData = this, isSettled = settled)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> mapped
|
else -> mapped
|
||||||
@@ -558,6 +589,34 @@ class UpgradeRepoGplay @Inject constructor(
|
|||||||
?.flatten()
|
?.flatten()
|
||||||
?: emptySet()
|
?: emptySet()
|
||||||
|
|
||||||
|
// Products with a payment Play is still processing. Deliberately NOT part of [isPro] or
|
||||||
|
// [upgrades]: a pending payment grants nothing. It exists so the UI can explain the wait
|
||||||
|
// and lock the purchase buttons — buying the alternative product now would double-charge.
|
||||||
|
val pendingSkus: Collection<Sku> = billingData?.pendingPurchases
|
||||||
|
?.map { purchase ->
|
||||||
|
purchase.products.mapNotNull { productId ->
|
||||||
|
val sku = OurSku.PRO_SKUS.singleOrNull { it.id == productId }
|
||||||
|
if (sku == null) {
|
||||||
|
log(TAG, WARN) { "Unknown pending product: $productId (${purchase.redacted()})" }
|
||||||
|
return@mapNotNull null
|
||||||
|
}
|
||||||
|
sku
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?.flatten()
|
||||||
|
?: emptySet()
|
||||||
|
|
||||||
|
// Any owned purchase Play still bills on a schedule. Deliberately computed from the RAW
|
||||||
|
// PURCHASED purchases instead of [upgrades]: the mapping drops products this app doesn't
|
||||||
|
// know, and the pre-purchase gate must keep blocking on a renewing subscription with an
|
||||||
|
// unknown or legacy product ID — being wrong there means billing the user twice for Pro.
|
||||||
|
// Both product types are scanned; a one-time purchase reports isAutoRenewing = false, so
|
||||||
|
// the broader input cannot produce a false positive.
|
||||||
|
// Computed on access, not in the initializer: an Info is built for every mapping pass, and
|
||||||
|
// only the purchase gate needs this.
|
||||||
|
val hasAutoRenewingSubscription: Boolean
|
||||||
|
get() = billingData?.purchases?.any { it.isAutoRenewing } == true
|
||||||
|
|
||||||
override val isPro: Boolean = upgrades.isNotEmpty() || gracePeriod
|
override val isPro: Boolean = upgrades.isNotEmpty() || gracePeriod
|
||||||
|
|
||||||
override val upgradedAt: Instant? = upgrades
|
override val upgradedAt: Instant? = upgrades
|
||||||
|
|||||||
@@ -1,7 +1,28 @@
|
|||||||
package eu.darken.capod.common.upgrade.core.billing
|
package eu.darken.capod.common.upgrade.core.billing
|
||||||
|
|
||||||
import com.android.billingclient.api.Purchase
|
import com.android.billingclient.api.Purchase
|
||||||
|
import eu.darken.capod.common.upgrade.core.billing.client.isPurchased
|
||||||
|
import eu.darken.capod.common.upgrade.core.billing.client.isRelevant
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Play's purchase state, split by what it may be used for. [purchases] is the entitlement carrier
|
||||||
|
* and PURCHASED-only by construction, so no consumer can grant Pro (or stamp the grace cache) from
|
||||||
|
* a payment Play is still processing; [pendingPurchases] keeps that payment visible to the UI.
|
||||||
|
*/
|
||||||
data class BillingData(
|
data class BillingData(
|
||||||
val purchases: Collection<Purchase>
|
val purchases: Collection<Purchase>,
|
||||||
)
|
val pendingPurchases: Collection<Purchase> = emptyList(),
|
||||||
|
) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// The one place raw Play data becomes a BillingData: splitting here (instead of at each
|
||||||
|
// consumer) is what keeps "pending never grants Pro" a property of the type. Anything
|
||||||
|
// that is neither PURCHASED nor PENDING is dropped — it is not an entitlement and not a
|
||||||
|
// payment in progress.
|
||||||
|
fun from(raw: Collection<Purchase>): BillingData {
|
||||||
|
val relevant = raw.filter { it.isRelevant }
|
||||||
|
val (purchased, pending) = relevant.partition { it.isPurchased }
|
||||||
|
return BillingData(purchases = purchased, pendingPurchases = pending)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ import eu.darken.capod.common.flow.setupCommonEventHandlers
|
|||||||
import eu.darken.capod.common.upgrade.core.billing.client.BillingClientException
|
import eu.darken.capod.common.upgrade.core.billing.client.BillingClientException
|
||||||
import eu.darken.capod.common.upgrade.core.billing.client.BillingConnection
|
import eu.darken.capod.common.upgrade.core.billing.client.BillingConnection
|
||||||
import eu.darken.capod.common.upgrade.core.billing.client.BillingConnectionProvider
|
import eu.darken.capod.common.upgrade.core.billing.client.BillingConnectionProvider
|
||||||
|
import eu.darken.capod.common.upgrade.core.billing.client.isPurchased
|
||||||
import eu.darken.capod.common.upgrade.core.billing.client.redacted
|
import eu.darken.capod.common.upgrade.core.billing.client.redacted
|
||||||
|
import eu.darken.capod.common.upgrade.core.billing.work.PurchaseAckScheduler
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
@@ -24,6 +26,8 @@ import kotlinx.coroutines.ensureActive
|
|||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed
|
import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.coroutines.withTimeoutOrNull
|
import kotlinx.coroutines.withTimeoutOrNull
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@@ -32,6 +36,7 @@ import javax.inject.Singleton
|
|||||||
class BillingManager @Inject constructor(
|
class BillingManager @Inject constructor(
|
||||||
@AppScope private val scope: CoroutineScope,
|
@AppScope private val scope: CoroutineScope,
|
||||||
connectionProvider: BillingConnectionProvider,
|
connectionProvider: BillingConnectionProvider,
|
||||||
|
private val ackScheduler: PurchaseAckScheduler,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// Fresh Play data plus its provenance: a query result covers owned products of the queried
|
// Fresh Play data plus its provenance: a query result covers owned products of the queried
|
||||||
@@ -73,13 +78,13 @@ class BillingManager @Inject constructor(
|
|||||||
private val failedOnce = MutableStateFlow(false)
|
private val failedOnce = MutableStateFlow(false)
|
||||||
val isFailureSettled: Flow<Boolean> = failedOnce
|
val isFailureSettled: Flow<Boolean> = failedOnce
|
||||||
|
|
||||||
// Fires once per failed connect-loop iteration: connection setup failure, the mandatory initial
|
// Fires once per reconciliation that couldn't confirm Pro: a failed connect-loop iteration
|
||||||
// refreshPurchases erroring or timing out, an established connection dropping, an action-level
|
// (connection setup failure, the mandatory initial refreshPurchases erroring or timing out, an
|
||||||
// invalidation (SERVICE_DISCONNECTED/SERVICE_TIMEOUT from any useConnection call), or an
|
// established connection dropping, an action-level invalidation, an unexpected provider
|
||||||
// unexpected provider completion. Every one is a fresh reconciliation that couldn't confirm Pro.
|
// completion) — and, via processReconciliation, a refresh that COMPLETED but only partially,
|
||||||
// The connect loop retries these internally and downstream flows just go quiet, so without this
|
// without a confirmed Pro purchase. The connect loop retries its failures internally and
|
||||||
// explicit signal the grace episode clock (UpgradeRepoGplay.proUnconfirmedSince) would only
|
// downstream flows just go quiet, so without this explicit signal the grace episode clock
|
||||||
// advance on an explicit ON_RESUME refresh().
|
// (UpgradeRepoGplay.proUnconfirmedSince) would only advance on an explicit ON_RESUME refresh().
|
||||||
//
|
//
|
||||||
// Each value is the failure's OCCURRENCE time (epoch millis). It has to be, not a bare Unit: the
|
// Each value is the failure's OCCURRENCE time (epoch millis). It has to be, not a bare Unit: the
|
||||||
// channel buffers, and this feed and freshBillingData are separate flows with no cross-stream
|
// channel buffers, and this feed and freshBillingData are separate flows with no cross-stream
|
||||||
@@ -121,13 +126,18 @@ class BillingManager @Inject constructor(
|
|||||||
// isFailureSettled forever with no retry. withTimeoutOrNull, NOT
|
// isFailureSettled forever with no retry. withTimeoutOrNull, NOT
|
||||||
// withTimeout: TimeoutCancellationException is a
|
// withTimeout: TimeoutCancellationException is a
|
||||||
// CancellationException and would kill this loop.
|
// CancellationException and would kill this loop.
|
||||||
withTimeoutOrNull(INITIAL_REFRESH_TIMEOUT_MS) {
|
val initialRefresh = withTimeoutOrNull(INITIAL_REFRESH_TIMEOUT_MS) {
|
||||||
connection.refreshPurchases()
|
connection.refreshPurchases()
|
||||||
} ?: throw BillingException("Initial purchase refresh timed out")
|
} ?: throw BillingException("Initial purchase refresh timed out")
|
||||||
|
|
||||||
failStreak = 0
|
failStreak = 0
|
||||||
connectionHolder.value = connection
|
connectionHolder.value = connection
|
||||||
log(TAG, INFO) { "Billing connection established" }
|
log(TAG, INFO) { "Billing connection established" }
|
||||||
|
// AFTER publishing: a partial refresh is still a usable connection
|
||||||
|
// (a pending-only cold start must not starve billingData), but its
|
||||||
|
// bookkeeping — episode clock, dead-binder teardown — has to run,
|
||||||
|
// and an invalidation may only tear down an INSTALLED connection.
|
||||||
|
processReconciliation(initialRefresh)
|
||||||
}
|
}
|
||||||
// The provider flow stays open for the connection's lifetime; a normal
|
// The provider flow stays open for the connection's lifetime; a normal
|
||||||
// completion means the connection is gone without an error — treat it
|
// completion means the connection is gone without an error — treat it
|
||||||
@@ -168,6 +178,11 @@ class BillingManager @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Serializes acknowledgement work between the reactive ack collector and explicit
|
||||||
|
// ensureAllAcknowledged() sweeps (PurchaseAckWorker): both paths mutate the token bookkeeping
|
||||||
|
// sets and both must never double-drive the same purchase's inline retry sequence.
|
||||||
|
private val ackMutex = Mutex()
|
||||||
|
|
||||||
// Re-drives the ack pass WITHOUT a new purchases emission: `purchases` is distinctUntilChanged,
|
// Re-drives the ack pass WITHOUT a new purchases emission: `purchases` is distinctUntilChanged,
|
||||||
// so a refresh returning a byte-identical (still unacknowledged) list is deduped and could never
|
// so a refresh returning a byte-identical (still unacknowledged) list is deduped and could never
|
||||||
// retry a failed ack -- the pipeline starved until Play sent something different. Declared ahead
|
// retry a failed ack -- the pipeline starved until Play sent something different. Declared ahead
|
||||||
@@ -214,7 +229,7 @@ class BillingManager @Inject constructor(
|
|||||||
.shareIn(scope, WhileSubscribed(3000L, 0L), replay = 1)
|
.shareIn(scope, WhileSubscribed(3000L, 0L), replay = 1)
|
||||||
|
|
||||||
val billingData: Flow<BillingData> = purchases
|
val billingData: Flow<BillingData> = purchases
|
||||||
.map { BillingData(purchases = it) }
|
.map { BillingData.from(it) }
|
||||||
.shareIn(scope, WhileSubscribed(3000L, 0L), replay = 1)
|
.shareIn(scope, WhileSubscribed(3000L, 0L), replay = 1)
|
||||||
|
|
||||||
val purchaseFailures: Flow<BillingResult> = connectionHolder
|
val purchaseFailures: Flow<BillingResult> = connectionHolder
|
||||||
@@ -235,7 +250,10 @@ class BillingManager @Inject constructor(
|
|||||||
// every emission here is a real Play round-trip the grace bookkeeping needs.
|
// every emission here is a real Play round-trip the grace bookkeeping needs.
|
||||||
.resubscribeOnFailure("freshBillingData")
|
.resubscribeOnFailure("freshBillingData")
|
||||||
}
|
}
|
||||||
.map { FreshData(data = BillingData(purchases = it.purchases), isFullSnapshot = it.isFullSnapshot, occurredAt = it.occurredAt) }
|
// Through from() like every other exit, although the connection only ever puts PURCHASED
|
||||||
|
// purchases on this stream: if that invariant ever broke, splitting keeps the grace
|
||||||
|
// bookkeeping from stamping a pending payment as a confirmation.
|
||||||
|
.map { FreshData(data = BillingData.from(it.purchases), isFullSnapshot = it.isFullSnapshot, occurredAt = it.occurredAt) }
|
||||||
.setupCommonEventHandlers(TAG) { "freshBillingData" }
|
.setupCommonEventHandlers(TAG) { "freshBillingData" }
|
||||||
// Same belt as `purchases`: an Eagerly shared flow that dies stays dead, and this one feeds
|
// Same belt as `purchases`: an Eagerly shared flow that dies stays dead, and this one feeds
|
||||||
// both the grace bookkeeping and the ack collector's re-drive signal.
|
// both the grace bookkeeping and the ack collector's re-drive signal.
|
||||||
@@ -247,13 +265,13 @@ class BillingManager @Inject constructor(
|
|||||||
// below. The immutable Purchase snapshot keeps reporting isAcknowledged=false until a fresh Play
|
// below. The immutable Purchase snapshot keeps reporting isAcknowledged=false until a fresh Play
|
||||||
// query supersedes it, so the ack re-fires every emission until then; re-acking is a documented
|
// query supersedes it, so the ack re-fires every emission until then; re-acking is a documented
|
||||||
// no-op on Play's side, whereas skipping a needed ack gets the purchase auto-refunded after 3
|
// no-op on Play's side, whereas skipping a needed ack gets the purchase auto-refunded after 3
|
||||||
// days -- so the ack stays unconditional and this set only quiets the log spam. Single
|
// days -- so the ack stays unconditional and this set only quiets the log spam. Confined by
|
||||||
// sequential collector (the ack pass below), no locking needed.
|
// ackMutex (the collector's pass and explicit sweeps both run under it).
|
||||||
private val loggedAckTokens = mutableSetOf<String>()
|
private val loggedAckTokens = mutableSetOf<String>()
|
||||||
|
|
||||||
// Tokens whose PERMANENT ack failure was already reported. Play will keep rejecting these
|
// Tokens whose PERMANENT ack failure was already reported. Play will keep rejecting these
|
||||||
// (developer error, item not owned, unsupported feature), so the bug report fires once per token
|
// (developer error, item not owned, unsupported feature), so the bug report fires once per token
|
||||||
// instead of once per pass. Same single-collector confinement as loggedAckTokens.
|
// instead of once per pass. Same ackMutex confinement as loggedAckTokens.
|
||||||
private val reportedAckFailures = mutableSetOf<String>()
|
private val reportedAckFailures = mutableSetOf<String>()
|
||||||
|
|
||||||
// At most one reschedule timer in flight: repeated failures must not stack timers.
|
// At most one reschedule timer in flight: repeated failures must not stack timers.
|
||||||
@@ -287,11 +305,22 @@ class BillingManager @Inject constructor(
|
|||||||
// .isAcknowledged, whose immutable snapshot stays false until a fresh Play query.
|
// .isAcknowledged, whose immutable snapshot stays false until a fresh Play query.
|
||||||
private enum class AckOutcome { SUCCESS, TRANSIENT, PERMANENT }
|
private enum class AckOutcome { SUCCESS, TRANSIENT, PERMANENT }
|
||||||
|
|
||||||
|
// Aggregate outcome of one ack pass; ensureAllAcknowledged() maps it to a sweep result.
|
||||||
|
data class AckPassOutcome(val transient: Int, val permanent: Int)
|
||||||
|
|
||||||
// One acknowledgement pass over the canonical purchase list. Never throws except cancellation:
|
// One acknowledgement pass over the canonical purchase list. Never throws except cancellation:
|
||||||
// transient failures schedule a re-drive, permanent ones are reported and left to organic fresh
|
// transient failures schedule a re-drive, permanent ones are reported and left to organic fresh
|
||||||
// -data signals.
|
// -data signals.
|
||||||
private suspend fun runAckPass(purchases: Collection<Purchase>) {
|
private suspend fun runAckPass(purchases: Collection<Purchase>): AckPassOutcome = ackMutex.withLock {
|
||||||
val needAck = purchases.filter {
|
val needAck = purchases.filter {
|
||||||
|
// The canonical list carries pending payments too. Play rejects acknowledging one
|
||||||
|
// PERMANENTLY, so an unfiltered pass would fire a bug report for every pending purchase,
|
||||||
|
// every pass — and there is nothing to acknowledge until the payment completes anyway.
|
||||||
|
if (!it.isPurchased) {
|
||||||
|
log(TAG) { "Not acknowledgeable yet: ${it.redacted()}" }
|
||||||
|
return@filter false
|
||||||
|
}
|
||||||
|
|
||||||
val needsAck = !it.isAcknowledged
|
val needsAck = !it.isAcknowledged
|
||||||
|
|
||||||
if (needsAck) log(TAG) { "Needs ACK: ${it.redacted()}" }
|
if (needsAck) log(TAG) { "Needs ACK: ${it.redacted()}" }
|
||||||
@@ -300,7 +329,23 @@ class BillingManager @Inject constructor(
|
|||||||
needsAck
|
needsAck
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (needAck.isNotEmpty()) {
|
||||||
|
// Arm the persistent safety net BEFORE attempting anything, and AWAIT the enqueue (the
|
||||||
|
// scheduler bounds it): the inline retries below can span minutes, and a process death
|
||||||
|
// inside them must not strand the purchase until Play's 3-day auto-refund. A deferred
|
||||||
|
// signal (channel + collector) would reintroduce exactly that window. Fail-open: the
|
||||||
|
// net is an extra layer, never a reason to skip the acks themselves.
|
||||||
|
try {
|
||||||
|
ackScheduler.armForUnackedPurchases(needAck.maxOf { it.purchaseTime } + ACK_SAFETY_NET_DEADLINE_MS)
|
||||||
|
} catch (e: CancellationException) {
|
||||||
|
throw e
|
||||||
|
} catch (e: Exception) {
|
||||||
|
log(TAG, WARN) { "Failed to arm ack safety net: ${e.asLog()}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var transientFailures = 0
|
var transientFailures = 0
|
||||||
|
var permanentFailures = 0
|
||||||
|
|
||||||
for (purchase in needAck) {
|
for (purchase in needAck) {
|
||||||
// First ack of a token is INFO; idempotent repeats drop to DEBUG. This never gates the
|
// First ack of a token is INFO; idempotent repeats drop to DEBUG. This never gates the
|
||||||
@@ -364,6 +409,7 @@ class BillingManager @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (outcome == AckOutcome.TRANSIENT) transientFailures++
|
if (outcome == AckOutcome.TRANSIENT) transientFailures++
|
||||||
|
if (outcome == AckOutcome.PERMANENT) permanentFailures++
|
||||||
if (abortPass) break
|
if (abortPass) break
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,6 +420,41 @@ class BillingManager @Inject constructor(
|
|||||||
}
|
}
|
||||||
scheduleAckRetry()
|
scheduleAckRetry()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AckPassOutcome(transient = transientFailures, permanent = permanentFailures)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Outcome of an explicit safety-net sweep, see ensureAllAcknowledged().
|
||||||
|
enum class AckSweepResult { COMPLETE, RETRY, PERMANENT_FAILURE }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One self-contained acknowledgement sweep for the persistent safety net (PurchaseAckWorker):
|
||||||
|
* refresh from Play, then acknowledge everything unacknowledged IN THIS COROUTINE. The reactive
|
||||||
|
* ack collector consumes purchase state asynchronously, so a caller that needs proof the acks
|
||||||
|
* actually happened before it reports success (a worker deciding success vs retry) cannot rely
|
||||||
|
* on it. Never throws except cancellation.
|
||||||
|
*/
|
||||||
|
suspend fun ensureAllAcknowledged(): AckSweepResult {
|
||||||
|
log(TAG) { "ensureAllAcknowledged()" }
|
||||||
|
val fresh = try {
|
||||||
|
useConnection { refreshPurchases() }
|
||||||
|
} catch (e: CancellationException) {
|
||||||
|
throw e
|
||||||
|
} catch (e: Exception) {
|
||||||
|
log(TAG, WARN) { "ensureAllAcknowledged(): refresh failed: ${e.asLog()}" }
|
||||||
|
return AckSweepResult.RETRY
|
||||||
|
}
|
||||||
|
// Same bookkeeping every other refresh exit owes: grace episode clock + dead-binder teardown.
|
||||||
|
processReconciliation(fresh)
|
||||||
|
val outcome = runAckPass(fresh.purchases)
|
||||||
|
return when {
|
||||||
|
// An incomplete refresh may be hiding an unacknowledged purchase of the failed type,
|
||||||
|
// and a transient ack failure is retriable by definition.
|
||||||
|
outcome.transient > 0 || !fresh.isComplete -> AckSweepResult.RETRY
|
||||||
|
// Play will keep rejecting these no matter how often the worker comes back.
|
||||||
|
outcome.permanent > 0 -> AckSweepResult.PERMANENT_FAILURE
|
||||||
|
else -> AckSweepResult.COMPLETE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A purchase Play will keep rejecting: report it once per token, then stay quiet. The pass still
|
// A purchase Play will keep rejecting: report it once per token, then stay quiet. The pass still
|
||||||
@@ -401,6 +482,39 @@ class BillingManager @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A partial refresh no longer reaches useConnection's dead-binder detection (it returns instead
|
||||||
|
// of throwing), so the teardown that used to ride the throw path happens here. Cause chain, not
|
||||||
|
// the exception itself: the failure arrives user-friendly-mapped. Deliberately no holder CAS:
|
||||||
|
// the failing connection may already have been replaced, and the accepted cost of that rare
|
||||||
|
// race is one extra failed action while the loop reconnects.
|
||||||
|
private fun invalidateOnDeadConnection(refresh: BillingConnection.PurchaseRefresh) {
|
||||||
|
val clientError = refresh.partialError?.let {
|
||||||
|
(it as? BillingClientException) ?: (it.cause as? BillingClientException)
|
||||||
|
}
|
||||||
|
if (clientError != null && clientError.result.responseCode in INVALIDATING_CODES) {
|
||||||
|
log(TAG, WARN) { "Refresh reported the connection dead (${clientError.result.responseCode}), invalidating." }
|
||||||
|
invalidations.trySend(Unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything a COMPLETED refresh owes the rest of the app, in one place: both the connect loop's
|
||||||
|
// initial refresh and manual refresh() calls run through it, so a Restore tap during an outage
|
||||||
|
// feeds the same bookkeeping the connect loop does. Only reached when refreshPurchases returned
|
||||||
|
// (it still throws when it found nothing AND a query failed — that path is the connect loop's /
|
||||||
|
// useConnection's).
|
||||||
|
private fun processReconciliation(refresh: BillingConnection.PurchaseRefresh) {
|
||||||
|
invalidateOnDeadConnection(refresh)
|
||||||
|
|
||||||
|
if (!refresh.isComplete && !refresh.hasConfirmedProPurchase) {
|
||||||
|
// A reconciliation that couldn't confirm Pro. Stamped with the refresh's COMMIT time,
|
||||||
|
// never now-at-send: a confirmation that committed between this refresh and the send
|
||||||
|
// (e.g. a pending payment completing) must stay NEWER than this failure, or the grace
|
||||||
|
// episode it closed would be reopened.
|
||||||
|
log(TAG, WARN) { "Partial refresh without a confirmed Pro purchase at ${refresh.occurredAt}" }
|
||||||
|
connectionFailuresChannel.trySend(refresh.occurredAt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun <T> useConnection(action: suspend BillingConnection.() -> T): T {
|
private suspend fun <T> useConnection(action: suspend BillingConnection.() -> T): T {
|
||||||
// Every caller here is active demand (opening the upgrade screen, restore/buy taps,
|
// Every caller here is active demand (opening the upgrade screen, restore/buy taps,
|
||||||
// purchase acks) — cut a pending reconnect backoff short. A no-op while healthy.
|
// purchase acks) — cut a pending reconnect backoff short. A no-op while healthy.
|
||||||
@@ -479,18 +593,29 @@ class BillingManager @Inject constructor(
|
|||||||
// shared upgradeInfo replay cache. The freshBillingData emission happens inside the
|
// shared upgradeInfo replay cache. The freshBillingData emission happens inside the
|
||||||
// reducer's commit, in commit order — not here.
|
// reducer's commit, in commit order — not here.
|
||||||
val fresh = useConnection { refreshPurchases() }
|
val fresh = useConnection { refreshPurchases() }
|
||||||
return BillingData(purchases = fresh.purchases)
|
processReconciliation(fresh)
|
||||||
|
return BillingData.from(fresh.purchases)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strict SUBS-only query for the pre-purchase subscription gate: unlike refresh(), a failure
|
// Strict variant for the pre-purchase gates: unlike refresh(), anything short of a COMPLETE
|
||||||
// here propagates (user-friendly-mapped) instead of being masked by the other product type.
|
// reconciliation throws (user-friendly-mapped) instead of returning what it happened to find —
|
||||||
suspend fun querySubscriptions(): Collection<Purchase> = try {
|
// a gate must be able to tell "not owned" apart from "couldn't verify" and fail closed.
|
||||||
useConnection { querySubscriptions() }
|
suspend fun refreshStrict(): BillingData {
|
||||||
} catch (e: CancellationException) {
|
log(TAG) { "refreshStrict()" }
|
||||||
throw e
|
val fresh = useConnection { refreshPurchases() }
|
||||||
} catch (e: Exception) {
|
// A gate that hit a dying connection must still trigger the reconnect (the throw below
|
||||||
log(TAG, WARN) { "querySubscriptions() failed: ${e.asLog()}" }
|
// bypasses useConnection's detection, which already returned), or every later purchase
|
||||||
throw e.tryMapUserFriendly()
|
// check keeps reusing the corpse. No-op on a complete refresh. The episode clock stays out
|
||||||
|
// of this path: an aborted gate is not a reconciliation outcome.
|
||||||
|
invalidateOnDeadConnection(fresh)
|
||||||
|
if (!fresh.isComplete) {
|
||||||
|
// partialError is set for every incomplete refresh; the fallback only exists so a
|
||||||
|
// future incompleteness without a captured cause still fails closed instead of passing.
|
||||||
|
val error = fresh.partialError ?: BillingException("Purchase refresh was incomplete")
|
||||||
|
log(TAG, WARN) { "refreshStrict() incomplete: ${error.asLog()}" }
|
||||||
|
throw error.tryMapUserFriendly()
|
||||||
|
}
|
||||||
|
return BillingData.from(fresh.purchases)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -525,6 +650,10 @@ class BillingManager @Inject constructor(
|
|||||||
BillingResponseCode.ITEM_NOT_OWNED,
|
BillingResponseCode.ITEM_NOT_OWNED,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Play auto-refunds purchases not acknowledged within 3 days; every safety-net deadline
|
||||||
|
// derives from this.
|
||||||
|
const val ACK_SAFETY_NET_DEADLINE_MS = 3 * 24 * 60 * 60 * 1000L
|
||||||
|
|
||||||
private const val INITIAL_REFRESH_TIMEOUT_MS = 30_000L
|
private const val INITIAL_REFRESH_TIMEOUT_MS = 30_000L
|
||||||
private const val MAX_BACKOFF_MS = 300_000L
|
private const val MAX_BACKOFF_MS = 300_000L
|
||||||
|
|
||||||
|
|||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package eu.darken.capod.common.upgrade.core.billing
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A purchase can't proceed because the account already has a payment Play is still processing.
|
||||||
|
*
|
||||||
|
* Typed so the UI can answer with the informational pending dialog instead of the already-owned
|
||||||
|
* error and its restore tips: restoring cannot help — Play refuses to re-sell a product with a
|
||||||
|
* pending payment, and the entitlement arrives on its own once the payment clears.
|
||||||
|
*/
|
||||||
|
class PendingPurchaseBillingException(cause: Throwable? = null) :
|
||||||
|
BillingException("A purchase with a pending payment already exists.", cause)
|
||||||
+15
@@ -8,6 +8,21 @@ import com.android.billingclient.api.Purchase
|
|||||||
internal val BillingResult.isSuccess: Boolean
|
internal val BillingResult.isSuccess: Boolean
|
||||||
get() = responseCode == BillingClient.BillingResponseCode.OK
|
get() = responseCode == BillingClient.BillingResponseCode.OK
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Owned right now. The ONLY state that may grant an entitlement, stamp the Pro grace cache or be
|
||||||
|
* acknowledged — a PENDING purchase is a payment Play is still processing, and acknowledging one is
|
||||||
|
* rejected permanently.
|
||||||
|
*/
|
||||||
|
internal val Purchase.isPurchased: Boolean
|
||||||
|
get() = purchaseState == Purchase.PurchaseState.PURCHASED
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Worth carrying in our state at all: owned, or a payment in progress the user should see. Anything
|
||||||
|
* else (UNSPECIFIED_STATE) is dropped at ingestion — it is neither.
|
||||||
|
*/
|
||||||
|
internal val Purchase.isRelevant: Boolean
|
||||||
|
get() = isPurchased || purchaseState == Purchase.PurchaseState.PENDING
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log-safe rendering of a [Purchase].
|
* Log-safe rendering of a [Purchase].
|
||||||
*
|
*
|
||||||
|
|||||||
+82
-70
@@ -7,7 +7,6 @@ import com.android.billingclient.api.BillingClient.BillingResponseCode
|
|||||||
import com.android.billingclient.api.BillingFlowParams
|
import com.android.billingclient.api.BillingFlowParams
|
||||||
import com.android.billingclient.api.BillingResult
|
import com.android.billingclient.api.BillingResult
|
||||||
import com.android.billingclient.api.Purchase
|
import com.android.billingclient.api.Purchase
|
||||||
import com.android.billingclient.api.Purchase.PurchaseState
|
|
||||||
import com.android.billingclient.api.QueryProductDetailsParams
|
import com.android.billingclient.api.QueryProductDetailsParams
|
||||||
import com.android.billingclient.api.QueryProductDetailsResult
|
import com.android.billingclient.api.QueryProductDetailsResult
|
||||||
import com.android.billingclient.api.QueryPurchasesParams
|
import com.android.billingclient.api.QueryPurchasesParams
|
||||||
@@ -41,11 +40,11 @@ class BillingConnection(
|
|||||||
private val skuTypeOf: (String) -> Sku.Type? = DEFAULT_SKU_TYPE_RESOLVER,
|
private val skuTypeOf: (String) -> Sku.Type? = DEFAULT_SKU_TYPE_RESOLVER,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// A purchase proven by an onPurchasesUpdated success event. Additive only: events prove
|
// A purchase (owned or with a pending payment) proven by an onPurchasesUpdated success event.
|
||||||
// ownership, never absence. `gen` orders it against queries (a query that STARTED before this
|
// Additive only: events prove existence, never absence. `gen` orders it against queries (a
|
||||||
// event must not clear it); `type` is resolved at ingestion so a later per-type query that
|
// query that STARTED before this event must not clear it); `type` is resolved at ingestion so a
|
||||||
// confirms absence can supersede it (null = product unknown to this app, only a complete
|
// later per-type query that confirms absence can supersede it (null = product unknown to this
|
||||||
// refresh may clear it).
|
// app, only a complete refresh may clear it).
|
||||||
data class OverlayEntry(
|
data class OverlayEntry(
|
||||||
val purchase: Purchase,
|
val purchase: Purchase,
|
||||||
val gen: Long,
|
val gen: Long,
|
||||||
@@ -64,11 +63,11 @@ class BillingConnection(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
internal fun withEvent(
|
internal fun withEvent(
|
||||||
purchased: Collection<Purchase>,
|
relevant: Collection<Purchase>,
|
||||||
typeOf: (String) -> Sku.Type?,
|
typeOf: (String) -> Sku.Type?,
|
||||||
): ReducerState {
|
): ReducerState {
|
||||||
val gen = eventGen + 1
|
val gen = eventGen + 1
|
||||||
val entries = purchased.map { purchase ->
|
val entries = relevant.map { purchase ->
|
||||||
OverlayEntry(
|
OverlayEntry(
|
||||||
purchase = purchase,
|
purchase = purchase,
|
||||||
gen = gen,
|
gen = gen,
|
||||||
@@ -169,10 +168,13 @@ class BillingConnection(
|
|||||||
"onPurchasesUpdated(code=${result.responseCode}, message=${result.debugMessage}, " +
|
"onPurchasesUpdated(code=${result.responseCode}, message=${result.debugMessage}, " +
|
||||||
"purchases=${purchases?.redacted()})"
|
"purchases=${purchases?.redacted()})"
|
||||||
}
|
}
|
||||||
// PENDING purchases must never surface as owned (or stamp the Pro grace cache).
|
// The reducer carries PENDING purchases too (the UI must be able to show a payment in
|
||||||
val purchased = purchases.orEmpty().filter { it.purchaseState == PurchaseState.PURCHASED }
|
// progress), but the fresh stream stays PURCHASED-only: it feeds the entitlement and
|
||||||
|
// grace bookkeeping, which must never see a payment Play hasn't completed.
|
||||||
|
val relevant = purchases.orEmpty().filter { it.isRelevant }
|
||||||
|
val purchased = relevant.filter { it.isPurchased }
|
||||||
synchronized(reducerLock) {
|
synchronized(reducerLock) {
|
||||||
state.value = state.value.withEvent(purchased, skuTypeOf)
|
state.value = state.value.withEvent(relevant, skuTypeOf)
|
||||||
if (purchased.isNotEmpty()) {
|
if (purchased.isNotEmpty()) {
|
||||||
freshUpdatesChannel.trySend(FreshUpdate(purchased, isFullSnapshot = false))
|
freshUpdatesChannel.trySend(FreshUpdate(purchased, isFullSnapshot = false))
|
||||||
}
|
}
|
||||||
@@ -193,12 +195,29 @@ class BillingConnection(
|
|||||||
failureChannel.close()
|
failureChannel.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// The purchases of a refresh plus whether it covered both product types: a partial result (one
|
// The full outcome of a refresh: what it committed, what it actually CONFIRMED, and how far it
|
||||||
// query failed) is still authoritative for what it FOUND, but must not be treated as proof of
|
// got. A partial result (one query failed) is still authoritative for what it found, but must
|
||||||
// absence for the type that couldn't be checked.
|
// not be treated as proof of absence for the type that couldn't be checked — so callers that
|
||||||
|
// need to fail closed, or to feed the grace episode clock, get the provenance instead of having
|
||||||
|
// to infer it from the merged view.
|
||||||
data class PurchaseRefresh(
|
data class PurchaseRefresh(
|
||||||
|
// The committed reducer state (queries merged with retained snapshots and surviving
|
||||||
|
// events) — the same view the reactive purchases flow emits.
|
||||||
val purchases: Collection<Purchase>,
|
val purchases: Collection<Purchase>,
|
||||||
|
// ONLY what these queries returned: never retained state of a failed type, so a consumer
|
||||||
|
// can tell "Play said so just now" from "we still remember this".
|
||||||
|
val confirmed: Collection<Purchase> = emptyList(),
|
||||||
|
// A confirmed PURCHASED purchase of a product this app knows. Fail-safe default: "we
|
||||||
|
// couldn't confirm Pro" is the direction that keeps the grace bookkeeping honest.
|
||||||
|
val hasConfirmedProPurchase: Boolean = false,
|
||||||
val isComplete: Boolean,
|
val isComplete: Boolean,
|
||||||
|
// Commit time under reducerLock — the same instant stamped on this refresh's FreshUpdate,
|
||||||
|
// so a confirmation and a later failure signal are ordered by when they HAPPENED.
|
||||||
|
val occurredAt: Long = System.currentTimeMillis(),
|
||||||
|
// Why the refresh is incomplete (the failed type's already user-friendly-mapped
|
||||||
|
// exception), null when complete. Carried rather than thrown: a partial refresh that found
|
||||||
|
// something is still useful, only the caller can decide whether partial is good enough.
|
||||||
|
val partialError: Throwable? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Serializes concurrent refreshes (manual, background, auto-restore): an older query that got
|
// Serializes concurrent refreshes (manual, background, auto-restore): an older query that got
|
||||||
@@ -214,8 +233,8 @@ class BillingConnection(
|
|||||||
coroutineScope {
|
coroutineScope {
|
||||||
log(TAG) { "refreshPurchases()" }
|
log(TAG) { "refreshPurchases()" }
|
||||||
val genAtQueryStart = state.value.eventGen
|
val genAtQueryStart = state.value.eventGen
|
||||||
val iapJob = async { queryPurchasedProducts(BillingClient.ProductType.INAPP) }
|
val iapJob = async { queryRelevantProducts(BillingClient.ProductType.INAPP) }
|
||||||
val subJob = async { queryPurchasedProducts(BillingClient.ProductType.SUBS) }
|
val subJob = async { queryRelevantProducts(BillingClient.ProductType.SUBS) }
|
||||||
val iap = iapJob.await()
|
val iap = iapJob.await()
|
||||||
val sub = subJob.await()
|
val sub = subJob.await()
|
||||||
log(TAG) { "Refreshed IAPs=${iap.getOrNull()?.redacted()}, SUBs=${sub.getOrNull()?.redacted()}" }
|
log(TAG) { "Refreshed IAPs=${iap.getOrNull()?.redacted()}, SUBs=${sub.getOrNull()?.redacted()}" }
|
||||||
@@ -224,6 +243,12 @@ class BillingConnection(
|
|||||||
// authoritative even when its sibling failed — verified absence (e.g. a refunded IAP)
|
// authoritative even when its sibling failed — verified absence (e.g. a refunded IAP)
|
||||||
// must not be discarded just because the SUB query errored.
|
// must not be discarded just because the SUB query errored.
|
||||||
val isComplete = iap.isSuccess && sub.isSuccess
|
val isComplete = iap.isSuccess && sub.isSuccess
|
||||||
|
// Only what the queries CONFIRMED as owned — retained stale data of a failed type, and
|
||||||
|
// pending payments, stay out (both would keep re-stamping the grace window).
|
||||||
|
val confirmed = (iap.getOrNull().orEmpty() + sub.getOrNull().orEmpty())
|
||||||
|
.filter { it.isPurchased }
|
||||||
|
.sortedByDescending { it.purchaseTime }
|
||||||
|
var committedAt = 0L
|
||||||
val committed = synchronized(reducerLock) {
|
val committed = synchronized(reducerLock) {
|
||||||
val next = state.value.withQueryResults(
|
val next = state.value.withQueryResults(
|
||||||
iap = iap.getOrNull(),
|
iap = iap.getOrNull(),
|
||||||
@@ -231,17 +256,18 @@ class BillingConnection(
|
|||||||
genAtQueryStart = genAtQueryStart,
|
genAtQueryStart = genAtQueryStart,
|
||||||
)
|
)
|
||||||
state.value = next
|
state.value = next
|
||||||
|
committedAt = System.currentTimeMillis()
|
||||||
if (iap.isSuccess || sub.isSuccess) {
|
if (iap.isSuccess || sub.isSuccess) {
|
||||||
// Only what the queries CONFIRMED — retained stale data of a failed type stays
|
// A surviving OWNED overlay entry (purchase event newer than the query start,
|
||||||
// out of the fresh stream (it would keep re-stamping the grace window).
|
// or of a failed type) means this result does NOT prove total absence: it must
|
||||||
val confirmed = (iap.getOrNull().orEmpty() + sub.getOrNull().orEmpty())
|
// not count as a full snapshot, or an empty query racing a fresh purchase event
|
||||||
.sortedByDescending { it.purchaseTime }
|
// would start a false unconfirmed-grace episode. A surviving PENDING entry
|
||||||
// A surviving overlay entry (purchase event newer than the query start, or of
|
// proves nothing about ownership, so it must not suppress the bookkeeping
|
||||||
// a failed type) means this result does NOT prove total absence: it must not
|
// either — a payment in progress would otherwise freeze the episode clock.
|
||||||
// count as a full snapshot, or an empty query racing a fresh purchase event
|
val provesAbsence = isComplete && next.overlay.none { it.purchase.isPurchased }
|
||||||
// would start a false unconfirmed-grace episode.
|
freshUpdatesChannel.trySend(
|
||||||
val provesAbsence = isComplete && next.overlay.isEmpty()
|
FreshUpdate(confirmed, isFullSnapshot = provesAbsence, occurredAt = committedAt)
|
||||||
freshUpdatesChannel.trySend(FreshUpdate(confirmed, isFullSnapshot = provesAbsence))
|
)
|
||||||
}
|
}
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
@@ -249,31 +275,42 @@ class BillingConnection(
|
|||||||
// Support-log anchor, at INFO because purchase complaints arrive as debug recordings.
|
// Support-log anchor, at INFO because purchase complaints arrive as debug recordings.
|
||||||
// Logs what these queries CONFIRMED, kept distinct from the committed view: merged()
|
// Logs what these queries CONFIRMED, kept distinct from the committed view: merged()
|
||||||
// retains a failed type's previous purchases, so reporting it as "what Play returned"
|
// retains a failed type's previous purchases, so reporting it as "what Play returned"
|
||||||
// would be the same false-certainty trap the copy elsewhere had to fix. Product IDs
|
// would be the same false-certainty trap the copy elsewhere had to fix. Pending ids are
|
||||||
// only -- never the Purchase, which carries order and token data.
|
// listed separately — "bought it, still not Pro" reports are exactly this state.
|
||||||
|
// Product IDs only -- never the Purchase, which carries order and token data.
|
||||||
log(TAG, INFO) {
|
log(TAG, INFO) {
|
||||||
val confirmedIds = (iap.getOrNull().orEmpty() + sub.getOrNull().orEmpty()).flatMap { it.products }
|
val returned = iap.getOrNull().orEmpty() + sub.getOrNull().orEmpty()
|
||||||
"refreshPurchases(): confirmed=$confirmedIds, isComplete=$isComplete, " +
|
val confirmedIds = returned.filter { it.isPurchased }.flatMap { it.products }
|
||||||
|
val pendingIds = returned.filterNot { it.isPurchased }.flatMap { it.products }
|
||||||
|
"refreshPurchases(): confirmed=$confirmedIds, pending=$pendingIds, isComplete=$isComplete, " +
|
||||||
"iapOk=${iap.isSuccess}, subOk=${sub.isSuccess}, merged=${committed.merged().size}"
|
"iapOk=${iap.isSuccess}, subOk=${sub.isSuccess}, merged=${committed.merged().size}"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Throws when nothing was found and a query failed, so the caller can tell "not
|
// Throws when nothing was found and a query failed, so the caller can tell "not
|
||||||
// owned" apart from "couldn't verify".
|
// owned" apart from "couldn't verify".
|
||||||
combinePurchaseResults(iap, sub)
|
combinePurchaseResults(iap, sub, skuTypeOf)
|
||||||
|
|
||||||
PurchaseRefresh(
|
PurchaseRefresh(
|
||||||
purchases = committed.merged(),
|
purchases = committed.merged(),
|
||||||
|
confirmed = confirmed,
|
||||||
|
hasConfirmedProPurchase = confirmed.any { purchase ->
|
||||||
|
purchase.products.any { skuTypeOf(it) != null }
|
||||||
|
},
|
||||||
isComplete = isComplete,
|
isComplete = isComplete,
|
||||||
|
occurredAt = committedAt,
|
||||||
|
partialError = iap.exceptionOrNull() ?: sub.exceptionOrNull(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Never throws except on cancellation, so a single failing product-type query doesn't cancel
|
// Never throws except on cancellation, so a single failing product-type query doesn't cancel
|
||||||
// the sibling query (or the coroutineScope). The exception is already user-friendly-mapped.
|
// the sibling query (or the coroutineScope). The exception is already user-friendly-mapped.
|
||||||
private suspend fun queryPurchasedProducts(
|
// Returns owned AND pending purchases; the split by state happens where it matters (fresh
|
||||||
|
// stream, entitlement mapping), so a pending payment stays visible instead of vanishing here.
|
||||||
|
private suspend fun queryRelevantProducts(
|
||||||
@BillingClient.ProductType type: String,
|
@BillingClient.ProductType type: String,
|
||||||
): Result<Collection<Purchase>> = try {
|
): Result<Collection<Purchase>> = try {
|
||||||
Result.success(queryPurchases(type).filter { it.purchaseState == PurchaseState.PURCHASED })
|
Result.success(queryPurchases(type).filter { it.isRelevant })
|
||||||
} catch (e: CancellationException) {
|
} catch (e: CancellationException) {
|
||||||
throw e
|
throw e
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -307,37 +344,6 @@ class BillingConnection(
|
|||||||
return purchaseData
|
return purchaseData
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strict SUBS-only query for the pre-purchase subscription gate: unlike refreshPurchases(),
|
|
||||||
// a failure propagates (no cross-type tolerance) — callers must be able to fail closed on
|
|
||||||
// "couldn't verify". Commits through the reducer like any query, so the reactive purchases
|
|
||||||
// flow picks up the fresh renewal state, and emits a partial fresh update: it proves what the
|
|
||||||
// SUBS query found, never the absence of anything it didn't cover.
|
|
||||||
suspend fun querySubscriptions(): Collection<Purchase> = refreshMutex.withLock {
|
|
||||||
log(TAG) { "querySubscriptions()" }
|
|
||||||
val genAtQueryStart = state.value.eventGen
|
|
||||||
val subs = queryPurchases(BillingClient.ProductType.SUBS)
|
|
||||||
.filter { it.purchaseState == PurchaseState.PURCHASED }
|
|
||||||
val committed = synchronized(reducerLock) {
|
|
||||||
val next = state.value.withQueryResults(
|
|
||||||
iap = null,
|
|
||||||
sub = subs,
|
|
||||||
genAtQueryStart = genAtQueryStart,
|
|
||||||
)
|
|
||||||
state.value = next
|
|
||||||
freshUpdatesChannel.trySend(FreshUpdate(subs, isFullSnapshot = false))
|
|
||||||
next
|
|
||||||
}
|
|
||||||
// The COMMITTED view, not the raw response: a purchase event that arrived after the query
|
|
||||||
// started survives the commit as a newer overlay and must reach the gate too — otherwise a
|
|
||||||
// just-purchased renewing sub could slip past the fail-closed double-billing check.
|
|
||||||
// Non-IAP overlays only; untyped (unknown product) entries stay in on the safe side.
|
|
||||||
val byToken = LinkedHashMap<String, Purchase>()
|
|
||||||
subs.forEach { byToken[it.purchaseToken] = it }
|
|
||||||
committed.overlay
|
|
||||||
.filter { it.type != Sku.Type.IAP }
|
|
||||||
.forEach { byToken[it.purchase.purchaseToken] = it.purchase }
|
|
||||||
byToken.values.sortedByDescending { it.purchaseTime }
|
|
||||||
}
|
|
||||||
suspend fun acknowledgePurchase(purchase: Purchase): BillingResult {
|
suspend fun acknowledgePurchase(purchase: Purchase): BillingResult {
|
||||||
val ack = AcknowledgePurchaseParams.newBuilder().apply {
|
val ack = AcknowledgePurchaseParams.newBuilder().apply {
|
||||||
setPurchaseToken(purchase.purchaseToken)
|
setPurchaseToken(purchase.purchaseToken)
|
||||||
@@ -529,16 +535,22 @@ class BillingConnection(
|
|||||||
OurSku.PRO_SKUS.singleOrNull { it.id == productId }?.type
|
OurSku.PRO_SKUS.singleOrNull { it.id == productId }?.type
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combines the two product-type query results: a purchase found by either type is
|
// Combines the two product-type query results: an error is only propagated when the refresh
|
||||||
// authoritative; an error is only propagated when nothing was found, so callers can tell
|
// learned nothing usable, so callers can tell "not owned" apart from "couldn't verify one
|
||||||
// "not owned" apart from "couldn't verify one product type". Treating any found purchase
|
// product type". A PURCHASED result of ANY product suppresses the error — every product
|
||||||
// as authoritative is safe because every product this app sells is a Pro SKU (see
|
// this app sells is a Pro SKU (see OurSku.PRO_SKUS), so it is by construction relevant. A
|
||||||
// OurSku.PRO_SKUS). Pure and unit-tested.
|
// PENDING result only counts when it maps to a KNOWN Pro SKU: it grants nothing, and an
|
||||||
|
// unknown pending product says nothing about the type whose query failed, so treating it
|
||||||
|
// as a find would swallow a real "couldn't verify". Pure and unit-tested.
|
||||||
internal fun combinePurchaseResults(
|
internal fun combinePurchaseResults(
|
||||||
iap: Result<Collection<Purchase>>,
|
iap: Result<Collection<Purchase>>,
|
||||||
sub: Result<Collection<Purchase>>,
|
sub: Result<Collection<Purchase>>,
|
||||||
|
typeOf: (String) -> Sku.Type? = DEFAULT_SKU_TYPE_RESOLVER,
|
||||||
): Collection<Purchase> {
|
): Collection<Purchase> {
|
||||||
val found = iap.getOrNull().orEmpty() + sub.getOrNull().orEmpty()
|
val returned = iap.getOrNull().orEmpty() + sub.getOrNull().orEmpty()
|
||||||
|
val found = returned.filter { purchase ->
|
||||||
|
purchase.isPurchased || purchase.products.any { typeOf(it) != null }
|
||||||
|
}
|
||||||
return when {
|
return when {
|
||||||
found.isNotEmpty() -> found.sortedByDescending { it.purchaseTime }
|
found.isNotEmpty() -> found.sortedByDescending { it.purchaseTime }
|
||||||
else -> {
|
else -> {
|
||||||
|
|||||||
+114
@@ -0,0 +1,114 @@
|
|||||||
|
package eu.darken.capod.common.upgrade.core.billing.work
|
||||||
|
|
||||||
|
import androidx.work.BackoffPolicy
|
||||||
|
import androidx.work.Constraints
|
||||||
|
import androidx.work.ExistingWorkPolicy
|
||||||
|
import androidx.work.NetworkType
|
||||||
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import androidx.work.await
|
||||||
|
import androidx.work.workDataOf
|
||||||
|
import eu.darken.capod.common.BuildConfigWrap
|
||||||
|
import eu.darken.capod.common.debug.logging.Logging.Priority.WARN
|
||||||
|
import eu.darken.capod.common.debug.logging.log
|
||||||
|
import eu.darken.capod.common.debug.logging.logTag
|
||||||
|
import eu.darken.capod.common.upgrade.core.billing.BillingManager
|
||||||
|
import kotlinx.coroutines.withTimeoutOrNull
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Provider
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arms the [PurchaseAckWorker] safety net. Two triggers:
|
||||||
|
* - a billing flow is about to launch (armed and awaited BEFORE the Play sheet, so the WorkManager
|
||||||
|
* DB transaction lands even if the process dies around the sheet),
|
||||||
|
* - an ack pass discovered unacknowledged purchases (called directly, pre-attempt, from
|
||||||
|
* BillingManager's runAckPass).
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
class PurchaseAckScheduler @Inject constructor(
|
||||||
|
// Resolved on the first arm, not at construction: fleet App classes eagerly inject the billing
|
||||||
|
// stack during Application field injection, and resolving WorkManager there can trigger its
|
||||||
|
// on-demand initialization before the Application's worker factory field is set.
|
||||||
|
private val workManager: Provider<WorkManager>,
|
||||||
|
) {
|
||||||
|
|
||||||
|
// A genuinely new flow refreshes the watch window: REPLACE the previous LAUNCH watch. The
|
||||||
|
// worker sweeps ALL unacknowledged purchases, so replacing an older watch loses nothing — and a
|
||||||
|
// pending rescue for an already-discovered purchase has its own identity, so starting another
|
||||||
|
// purchase can never displace it. The long delay keeps the worker out of the window where the
|
||||||
|
// user may still be in the Play sheet.
|
||||||
|
suspend fun armForBillingFlowLaunch() = arm(
|
||||||
|
name = WORK_NAME_LAUNCH,
|
||||||
|
policy = ExistingWorkPolicy.REPLACE,
|
||||||
|
expiresAt = System.currentTimeMillis() + BillingManager.ACK_SAFETY_NET_DEADLINE_MS,
|
||||||
|
initialDelayMs = LAUNCH_DELAY_MS,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Any pending rescue already covers every unacknowledged purchase: KEEP it. Once completed
|
||||||
|
// work exists, KEEP inserts a fresh request. Short delay — the purchase already EXISTS (unlike
|
||||||
|
// the launch trigger), possibly for days, so waiting 30min could waste real deadline time.
|
||||||
|
// Accepted edge of KEEP, within the rescue lane only: a pending request keeps its original
|
||||||
|
// (possibly earlier) expiry; a newer purchase with a later deadline is only re-covered once a
|
||||||
|
// later pass re-arms after the old work completed. Bounded residual, only reachable via
|
||||||
|
// out-of-band purchases.
|
||||||
|
suspend fun armForUnackedPurchases(expiresAt: Long) = arm(
|
||||||
|
name = WORK_NAME_RESCUE,
|
||||||
|
policy = ExistingWorkPolicy.KEEP,
|
||||||
|
expiresAt = expiresAt,
|
||||||
|
initialDelayMs = DISCOVERY_DELAY_MS,
|
||||||
|
)
|
||||||
|
|
||||||
|
private suspend fun arm(
|
||||||
|
name: String,
|
||||||
|
policy: ExistingWorkPolicy,
|
||||||
|
expiresAt: Long,
|
||||||
|
initialDelayMs: Long,
|
||||||
|
) {
|
||||||
|
if (expiresAt <= System.currentTimeMillis()) {
|
||||||
|
// Play has already voided (or is about to void) such a purchase; a sweep can't help.
|
||||||
|
log(TAG, WARN) { "arm($policy): deadline $expiresAt already passed, not scheduling" }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val request = OneTimeWorkRequestBuilder<PurchaseAckWorker>().apply {
|
||||||
|
setConstraints(
|
||||||
|
Constraints.Builder().apply {
|
||||||
|
setRequiredNetworkType(NetworkType.CONNECTED)
|
||||||
|
}.build()
|
||||||
|
)
|
||||||
|
// Launch trigger: the worker must not run while the user may still be in the Play
|
||||||
|
// sheet — an immediate sweep would find nothing unacknowledged, report success, and
|
||||||
|
// complete the net before the purchase it exists for even happened.
|
||||||
|
setInitialDelay(initialDelayMs, TimeUnit.MILLISECONDS)
|
||||||
|
setBackoffCriteria(BackoffPolicy.EXPONENTIAL, BACKOFF_DELAY_MS, TimeUnit.MILLISECONDS)
|
||||||
|
setInputData(workDataOf(PurchaseAckWorker.KEY_EXPIRES_AT to expiresAt))
|
||||||
|
}.build()
|
||||||
|
|
||||||
|
// Await the enqueue: the caller arms this because the process may die at any moment — a
|
||||||
|
// fire-and-forget enqueue could be lost with it. Cancellable and BOUNDED: every caller
|
||||||
|
// needs a durable enqueue without an unbounded stall — a WorkManager that never settles
|
||||||
|
// must become an exception (handled fail-open by every caller) instead of a hang (which on
|
||||||
|
// the launch lane would park the purchase and its busy guard forever).
|
||||||
|
val operation = workManager.get().enqueueUniqueWork(name, policy, request)
|
||||||
|
withTimeoutOrNull(ENQUEUE_TIMEOUT_MS) { operation.await() }
|
||||||
|
?: throw IllegalStateException("WorkManager enqueue did not settle within ${ENQUEUE_TIMEOUT_MS}ms")
|
||||||
|
log(TAG) { "arm($policy): safety net armed, expiresAt=$expiresAt" }
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// WorkManager persists these names AND the worker's class name in its DB across app
|
||||||
|
// updates: keep all of them stable while old work may exist (hence the version suffix for
|
||||||
|
// future changes). Separate identities per trigger: the launch watch's REPLACE must not be
|
||||||
|
// able to displace a pending rescue for a purchase that already exists.
|
||||||
|
private val WORK_NAME_LAUNCH = "${BuildConfigWrap.APPLICATION_ID}.gplay.purchase-ack.launch.v1"
|
||||||
|
private val WORK_NAME_RESCUE = "${BuildConfigWrap.APPLICATION_ID}.gplay.purchase-ack.rescue.v1"
|
||||||
|
|
||||||
|
private const val LAUNCH_DELAY_MS = 30 * 60 * 1000L
|
||||||
|
private const val DISCOVERY_DELAY_MS = 60 * 1000L
|
||||||
|
private const val BACKOFF_DELAY_MS = 30 * 60 * 1000L
|
||||||
|
private const val ENQUEUE_TIMEOUT_MS = 10 * 1000L
|
||||||
|
|
||||||
|
val TAG: String = logTag("Upgrade", "Gplay", "Billing", "AckScheduler")
|
||||||
|
}
|
||||||
|
}
|
||||||
+86
@@ -0,0 +1,86 @@
|
|||||||
|
package eu.darken.capod.common.upgrade.core.billing.work
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.hilt.work.HiltWorker
|
||||||
|
import androidx.work.CoroutineWorker
|
||||||
|
import androidx.work.ListenableWorker.Result
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import eu.darken.capod.common.debug.logging.Logging.Priority.INFO
|
||||||
|
import eu.darken.capod.common.debug.logging.Logging.Priority.WARN
|
||||||
|
import eu.darken.capod.common.debug.logging.log
|
||||||
|
import eu.darken.capod.common.debug.logging.logTag
|
||||||
|
import eu.darken.capod.common.upgrade.core.billing.BillingManager
|
||||||
|
import kotlinx.coroutines.withTimeoutOrNull
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persistent acknowledgement safety net, armed by [PurchaseAckScheduler].
|
||||||
|
*
|
||||||
|
* Play auto-refunds (and revokes) any purchase not acknowledged within 3 days. The in-process ack
|
||||||
|
* machinery in [BillingManager] handles every case where the process lives long enough — this
|
||||||
|
* worker covers the case it can't: the process dies around the Play purchase sheet (OEM task
|
||||||
|
* killers) and the user doesn't reopen the app before the deadline. Play voids such purchases and
|
||||||
|
* revokes the entitlement, so the user loses what they signed up for.
|
||||||
|
*
|
||||||
|
* Self-completing by design: nothing cancels this work from the foreground ack path (an ack pass
|
||||||
|
* can legitimately see zero unacknowledged purchases while the Play sheet is still open, which
|
||||||
|
* must not tear down the net). The redundant sweep after a successful foreground ack is one
|
||||||
|
* purchase query.
|
||||||
|
*/
|
||||||
|
@HiltWorker
|
||||||
|
class PurchaseAckWorker @AssistedInject constructor(
|
||||||
|
@Assisted private val context: Context,
|
||||||
|
@Assisted private val params: WorkerParameters,
|
||||||
|
private val billingManager: BillingManager,
|
||||||
|
) : CoroutineWorker(context, params) {
|
||||||
|
|
||||||
|
override suspend fun doWork(): Result {
|
||||||
|
val expiresAt = inputData.getLong(KEY_EXPIRES_AT, 0L)
|
||||||
|
log(TAG) { "doWork(): attempt=$runAttemptCount, expiresAt=$expiresAt" }
|
||||||
|
|
||||||
|
if (!isWorthSweeping(System.currentTimeMillis(), expiresAt)) {
|
||||||
|
// Past Play's refund deadline (or malformed input): retrying can't achieve anything.
|
||||||
|
// failure() is deliberate over success() — it is visible in WorkManager diagnostics,
|
||||||
|
// and a completed state lets a later KEEP enqueue insert fresh work.
|
||||||
|
log(TAG, WARN) { "doWork(): deadline passed, giving up" }
|
||||||
|
return Result.failure()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bounded well below WorkManager's 10-minute execution limit, but generous enough for the
|
||||||
|
// connection wait plus the per-purchase inline retries. A sweep that ran out of time is a
|
||||||
|
// transient outcome, not a verdict. External cancellation propagates out of doWork — it
|
||||||
|
// must never be converted into success.
|
||||||
|
val sweep = withTimeoutOrNull(SWEEP_TIMEOUT_MS) {
|
||||||
|
billingManager.ensureAllAcknowledged()
|
||||||
|
}
|
||||||
|
log(TAG, INFO) { "doWork(): sweep=$sweep" }
|
||||||
|
|
||||||
|
return mapSweep(sweep, System.currentTimeMillis(), expiresAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// Persisted in WorkManager's request data — keep the key stable while old work may exist.
|
||||||
|
const val KEY_EXPIRES_AT = "purchase.ack.expiresAt"
|
||||||
|
|
||||||
|
private const val SWEEP_TIMEOUT_MS = 4 * 60 * 1000L
|
||||||
|
|
||||||
|
// Pure so the retry/expiry decision is unit-testable without a WorkManager test harness.
|
||||||
|
internal fun isWorthSweeping(now: Long, expiresAt: Long): Boolean =
|
||||||
|
expiresAt > 0L && now < expiresAt
|
||||||
|
|
||||||
|
internal fun mapSweep(
|
||||||
|
sweep: BillingManager.AckSweepResult?,
|
||||||
|
now: Long,
|
||||||
|
expiresAt: Long,
|
||||||
|
): Result = when (sweep) {
|
||||||
|
BillingManager.AckSweepResult.COMPLETE -> Result.success()
|
||||||
|
BillingManager.AckSweepResult.PERMANENT_FAILURE -> Result.failure()
|
||||||
|
// RETRY or timeout (null): keep trying until the deadline. WorkManager's exponential
|
||||||
|
// backoff caps at 5h, so the 3-day window still yields many attempts.
|
||||||
|
else -> if (now < expiresAt) Result.retry() else Result.failure()
|
||||||
|
}
|
||||||
|
|
||||||
|
val TAG: String = logTag("Upgrade", "Gplay", "Billing", "AckWorker")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,5 +13,14 @@ sealed class UpgradeEvents {
|
|||||||
*/
|
*/
|
||||||
data object RestoreInconclusive : UpgradeEvents()
|
data object RestoreInconclusive : UpgradeEvents()
|
||||||
data object SubscriptionStillRenewing : UpgradeEvents()
|
data object SubscriptionStillRenewing : UpgradeEvents()
|
||||||
data object SubscriptionCheckFailed : UpgradeEvents()
|
|
||||||
|
/**
|
||||||
|
* Play answered, no completed purchase exists, but a payment is still being processed. Purely
|
||||||
|
* informational: nothing to fix, nothing to restore — Pro unlocks by itself once Play clears
|
||||||
|
* the payment, and a new purchase would be rejected (or double-charge) in the meantime.
|
||||||
|
*/
|
||||||
|
data object PurchasePending : UpgradeEvents()
|
||||||
|
|
||||||
|
/** The pre-purchase check with Play didn't finish, so the purchase was not started. */
|
||||||
|
data object PurchaseCheckFailed : UpgradeEvents()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.size
|
|||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.twotone.Autorenew
|
import androidx.compose.material.icons.twotone.Autorenew
|
||||||
|
import androidx.compose.material.icons.twotone.HourglassTop
|
||||||
import androidx.compose.material.icons.twotone.Verified
|
import androidx.compose.material.icons.twotone.Verified
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.CardDefaults
|
import androidx.compose.material3.CardDefaults
|
||||||
@@ -101,8 +102,10 @@ internal fun UpgradeOwnershipContent(
|
|||||||
Button(
|
Button(
|
||||||
onClick = onIap,
|
onClick = onIap,
|
||||||
// Not gated on iapEnabled: prices may have failed to load while the purchase
|
// Not gated on iapEnabled: prices may have failed to load while the purchase
|
||||||
// itself would work (the billing flow re-queries details on launch).
|
// itself would work (the billing flow re-queries details on launch). A pending
|
||||||
enabled = switchUnlocked && uiState.busy == null,
|
// payment does lock it — Play would reject the purchase, and the pending card
|
||||||
|
// above carries the explanation.
|
||||||
|
enabled = switchUnlocked && uiState.busy == null && !uiState.hasPendingPurchase,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.testTag(UpgradeScreenTags.GPLAY_IAP),
|
.testTag(UpgradeScreenTags.GPLAY_IAP),
|
||||||
@@ -239,6 +242,38 @@ internal fun UpgradeGraceCard(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shown to EVERY audience while Google Play is still processing a payment: an acquisition user who
|
||||||
|
// just bought, an owner buying the other product, and a grace user whose Pro is running out — all
|
||||||
|
// three have purchase actions locked and need the same explanation. Calm reassurance styling like
|
||||||
|
// the grace card: nothing is wrong, the payment just isn't done.
|
||||||
|
@Composable
|
||||||
|
internal fun PendingPurchaseCard(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
UpgradeSectionCard(
|
||||||
|
title = stringResource(R.string.upgrade_screen_pending_card_title),
|
||||||
|
icon = Icons.TwoTone.HourglassTop,
|
||||||
|
modifier = modifier.testTag(UpgradeScreenTags.GPLAY_PENDING),
|
||||||
|
colors = CardDefaults.elevatedCardColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.secondaryContainer,
|
||||||
|
contentColor = MaterialTheme.colorScheme.onSecondaryContainer,
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.upgrade_screen_pending_card_body),
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview2
|
||||||
|
@Composable
|
||||||
|
private fun PendingPurchaseCardPreview() {
|
||||||
|
PreviewWrapper {
|
||||||
|
PendingPurchaseCard()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun previewLoadedState(ownership: Ownership) = GplayUpgradeUiState.Loaded(
|
private fun previewLoadedState(ownership: Ownership) = GplayUpgradeUiState.Loaded(
|
||||||
subscriptionAction = SubscriptionAction.UNAVAILABLE,
|
subscriptionAction = SubscriptionAction.UNAVAILABLE,
|
||||||
subscriptionEnabled = false,
|
subscriptionEnabled = false,
|
||||||
|
|||||||
@@ -42,6 +42,12 @@ import eu.darken.capod.common.error.ErrorEventHandler
|
|||||||
import eu.darken.capod.common.navigation.NavigationEventHandler
|
import eu.darken.capod.common.navigation.NavigationEventHandler
|
||||||
import eu.darken.capod.common.navigation.Nav
|
import eu.darken.capod.common.navigation.Nav
|
||||||
|
|
||||||
|
// The Settings row reads this so it can't name the tier differently than this screen's own
|
||||||
|
// composed title does. FOSS's counterpart in its own UpgradeScreen.kt stays a support ask instead
|
||||||
|
// of the composed brand title; each flavor implementation lives only in its own source set.
|
||||||
|
@Composable
|
||||||
|
internal fun settingsUpgradeStatusTitle(): String = brandTitleText(includeQualifier = true)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UpgradeScreenHost(
|
fun UpgradeScreenHost(
|
||||||
route: Nav.Main.Upgrade = Nav.Main.Upgrade(),
|
route: Nav.Main.Upgrade = Nav.Main.Upgrade(),
|
||||||
@@ -64,6 +70,7 @@ fun UpgradeScreenHost(
|
|||||||
var showRestoreInconclusive by rememberSaveable { mutableStateOf(false) }
|
var showRestoreInconclusive by rememberSaveable { mutableStateOf(false) }
|
||||||
var showStillRenewing by rememberSaveable { mutableStateOf(false) }
|
var showStillRenewing by rememberSaveable { mutableStateOf(false) }
|
||||||
var showCheckFailed by rememberSaveable { mutableStateOf(false) }
|
var showCheckFailed by rememberSaveable { mutableStateOf(false) }
|
||||||
|
var showPurchasePending by rememberSaveable { mutableStateOf(false) }
|
||||||
|
|
||||||
LaunchedEffect(vm) {
|
LaunchedEffect(vm) {
|
||||||
vm.events.collect { event ->
|
vm.events.collect { event ->
|
||||||
@@ -77,7 +84,8 @@ fun UpgradeScreenHost(
|
|||||||
UpgradeEvents.RestoreFailed -> showRestoreFailed = true
|
UpgradeEvents.RestoreFailed -> showRestoreFailed = true
|
||||||
UpgradeEvents.RestoreInconclusive -> showRestoreInconclusive = true
|
UpgradeEvents.RestoreInconclusive -> showRestoreInconclusive = true
|
||||||
UpgradeEvents.SubscriptionStillRenewing -> showStillRenewing = true
|
UpgradeEvents.SubscriptionStillRenewing -> showStillRenewing = true
|
||||||
UpgradeEvents.SubscriptionCheckFailed -> showCheckFailed = true
|
UpgradeEvents.PurchaseCheckFailed -> showCheckFailed = true
|
||||||
|
UpgradeEvents.PurchasePending -> showPurchasePending = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -128,7 +136,7 @@ fun UpgradeScreenHost(
|
|||||||
if (showCheckFailed) {
|
if (showCheckFailed) {
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
onDismissRequest = { showCheckFailed = false },
|
onDismissRequest = { showCheckFailed = false },
|
||||||
text = { Text(text = stringResource(R.string.upgrade_screen_sub_check_failed_message)) },
|
text = { Text(text = stringResource(R.string.upgrade_screen_purchase_check_failed_message)) },
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
TextButton(onClick = { showCheckFailed = false }) {
|
TextButton(onClick = { showCheckFailed = false }) {
|
||||||
Text(text = stringResource(R.string.general_close_action))
|
Text(text = stringResource(R.string.general_close_action))
|
||||||
@@ -137,6 +145,10 @@ fun UpgradeScreenHost(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (showPurchasePending) {
|
||||||
|
PurchasePendingDialog(onDismiss = { showPurchasePending = false })
|
||||||
|
}
|
||||||
|
|
||||||
val uiState by vm.state.collectAsStateWithLifecycle()
|
val uiState by vm.state.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
UpgradeScreen(
|
UpgradeScreen(
|
||||||
@@ -181,6 +193,34 @@ internal fun RestoreFailedDialog(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shown when Play is still processing a payment. Purely informational: there is nothing to fix, no
|
||||||
|
* purchase to restore and no support case — the entitlement arrives on its own once the payment
|
||||||
|
* clears, so the dialog offers only a dismiss.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
internal fun PurchasePendingDialog(
|
||||||
|
onDismiss: () -> Unit = {},
|
||||||
|
) {
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = onDismiss,
|
||||||
|
text = { Text(text = stringResource(R.string.upgrade_screen_pending_dialog_message)) },
|
||||||
|
confirmButton = {
|
||||||
|
TextButton(onClick = onDismiss) {
|
||||||
|
Text(text = stringResource(R.string.general_close_action))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview2
|
||||||
|
@Composable
|
||||||
|
private fun PurchasePendingDialogPreview() {
|
||||||
|
PreviewWrapper {
|
||||||
|
PurchasePendingDialog()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shown when the restore never got an answer (timeout, or a Play error absorbed by grace). Carries
|
* Shown when the restore never got an answer (timeout, or a Play error absorbed by grace). Carries
|
||||||
* no multi-account hint and no contact-support action: nothing was established, so both would be
|
* no multi-account hint and no contact-support action: nothing was established, so both would be
|
||||||
@@ -275,6 +315,12 @@ internal fun UpgradeScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Above the ownership/acquisition split, because a pending payment cuts across it: the
|
||||||
|
// buyer waiting for their first Pro purchase, the owner switching products and the
|
||||||
|
// grace user (whose offers box is hidden entirely) all need it, and it is the reason
|
||||||
|
// their purchase buttons are locked.
|
||||||
|
if (loaded?.hasPendingPurchase == true) PendingPurchaseCard()
|
||||||
|
|
||||||
if (ownedState != null) {
|
if (ownedState != null) {
|
||||||
UpgradeOwnershipContent(
|
UpgradeOwnershipContent(
|
||||||
uiState = ownedState,
|
uiState = ownedState,
|
||||||
@@ -480,6 +526,24 @@ private fun UpgradeScreenReturningBuyerPreview() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The acquisition variant of the pending state: card above the offers, both buy buttons locked.
|
||||||
|
@Preview2
|
||||||
|
@Composable
|
||||||
|
private fun UpgradeScreenPendingPreview() {
|
||||||
|
PreviewWrapper {
|
||||||
|
UpgradeScreen(
|
||||||
|
uiState = GplayUpgradeUiState.Loaded(
|
||||||
|
subscriptionAction = SubscriptionAction.STANDARD,
|
||||||
|
subscriptionEnabled = false,
|
||||||
|
subscriptionPrice = "$12.99",
|
||||||
|
iapEnabled = false,
|
||||||
|
iapPrice = "$24.99",
|
||||||
|
hasPendingPurchase = true,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Preview2
|
@Preview2
|
||||||
@Composable
|
@Composable
|
||||||
private fun UpgradeScreenUnavailablePreview() {
|
private fun UpgradeScreenUnavailablePreview() {
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ internal sealed interface GplayUpgradeUiState {
|
|||||||
val ownership: Ownership = Ownership(),
|
val ownership: Ownership = Ownership(),
|
||||||
val grace: GraceHint? = null,
|
val grace: GraceHint? = null,
|
||||||
val wasPreviouslyPro: Boolean = false,
|
val wasPreviouslyPro: Boolean = false,
|
||||||
|
// A payment Google Play is still processing. SKU-agnostic on purpose: the card explains the
|
||||||
|
// wait and both purchase actions lock, regardless of which product is pending.
|
||||||
|
val hasPendingPurchase: Boolean = false,
|
||||||
val busy: BusyOp? = null,
|
val busy: BusyOp? = null,
|
||||||
) : GplayUpgradeUiState
|
) : GplayUpgradeUiState
|
||||||
}
|
}
|
||||||
@@ -73,12 +76,18 @@ internal fun UpgradeRepoGplay.Info.toOwnership() = Ownership(
|
|||||||
?.let { subs -> SubscriptionOwnership(isAutoRenewing = subs.any { it.purchase.isAutoRenewing }) },
|
?.let { subs -> SubscriptionOwnership(isAutoRenewing = subs.any { it.purchase.isAutoRenewing }) },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Any Pro payment Play is still processing. No per-product flag: the one-time purchase and the
|
||||||
|
// subscription are alternatives, so a pending payment for either one must lock both — completing
|
||||||
|
// both would charge the user twice for the same thing.
|
||||||
|
internal fun UpgradeRepoGplay.Info.toPendingFlag(): Boolean = pendingSkus.isNotEmpty()
|
||||||
|
|
||||||
internal fun toLoadedState(
|
internal fun toLoadedState(
|
||||||
iap: SkuDetails?,
|
iap: SkuDetails?,
|
||||||
sub: SkuDetails?,
|
sub: SkuDetails?,
|
||||||
ownership: Ownership,
|
ownership: Ownership,
|
||||||
grace: GraceHint? = null,
|
grace: GraceHint? = null,
|
||||||
wasPreviouslyPro: Boolean = false,
|
wasPreviouslyPro: Boolean = false,
|
||||||
|
hasPendingPurchase: Boolean = false,
|
||||||
busy: BusyOp? = null,
|
busy: BusyOp? = null,
|
||||||
): GplayUpgradeUiState.Loaded {
|
): GplayUpgradeUiState.Loaded {
|
||||||
val iapOffer = iap?.details?.oneTimePurchaseOfferDetails
|
val iapOffer = iap?.details?.oneTimePurchaseOfferDetails
|
||||||
@@ -97,15 +106,18 @@ internal fun toLoadedState(
|
|||||||
},
|
},
|
||||||
// Any running entitlement operation (restore, manual or the invisible already-owned
|
// Any running entitlement operation (restore, manual or the invisible already-owned
|
||||||
// recovery, and purchases) pauses the buy actions too — starting a purchase while an
|
// recovery, and purchases) pauses the buy actions too — starting a purchase while an
|
||||||
// entitlement is being reconciled just races Play into ITEM_ALREADY_OWNED.
|
// entitlement is being reconciled just races Play into ITEM_ALREADY_OWNED. A pending
|
||||||
|
// payment locks BOTH offers for the same reason the card explains: Play refuses the
|
||||||
|
// re-purchase, and the alternative product would double-charge for the same features.
|
||||||
subscriptionEnabled = (subOffer != null || subOfferTrial != null) &&
|
subscriptionEnabled = (subOffer != null || subOfferTrial != null) &&
|
||||||
ownership.subscription == null && busy == null,
|
ownership.subscription == null && busy == null && !hasPendingPurchase,
|
||||||
subscriptionPrice = subOffer?.pricingPhases?.pricingPhaseList?.lastOrNull()?.formattedPrice,
|
subscriptionPrice = subOffer?.pricingPhases?.pricingPhaseList?.lastOrNull()?.formattedPrice,
|
||||||
iapEnabled = iapOffer != null && !ownership.hasIap && busy == null,
|
iapEnabled = iapOffer != null && !ownership.hasIap && busy == null && !hasPendingPurchase,
|
||||||
iapPrice = iapOffer?.formattedPrice,
|
iapPrice = iapOffer?.formattedPrice,
|
||||||
ownership = ownership,
|
ownership = ownership,
|
||||||
grace = grace,
|
grace = grace,
|
||||||
wasPreviouslyPro = wasPreviouslyPro,
|
wasPreviouslyPro = wasPreviouslyPro,
|
||||||
|
hasPendingPurchase = hasPendingPurchase,
|
||||||
busy = busy,
|
busy = busy,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import eu.darken.capod.common.upgrade.core.OurSku
|
|||||||
import eu.darken.capod.common.upgrade.core.UpgradeRepoGplay
|
import eu.darken.capod.common.upgrade.core.UpgradeRepoGplay
|
||||||
import eu.darken.capod.common.upgrade.core.billing.GplayServiceUnavailableException
|
import eu.darken.capod.common.upgrade.core.billing.GplayServiceUnavailableException
|
||||||
import eu.darken.capod.common.upgrade.core.billing.OfferUnavailableBillingException
|
import eu.darken.capod.common.upgrade.core.billing.OfferUnavailableBillingException
|
||||||
|
import eu.darken.capod.common.upgrade.core.billing.PendingPurchaseBillingException
|
||||||
import eu.darken.capod.common.upgrade.core.billing.Sku
|
import eu.darken.capod.common.upgrade.core.billing.Sku
|
||||||
import eu.darken.capod.common.upgrade.core.billing.SkuDetails
|
import eu.darken.capod.common.upgrade.core.billing.SkuDetails
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
@@ -161,8 +162,10 @@ class UpgradeViewModel @Inject constructor(
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
// Owners and grace users don't depend on offer prices: their status and management
|
// Owners and grace users don't depend on offer prices: their status and management
|
||||||
// actions render immediately and price problems are not their problem.
|
// actions render immediately and price problems are not their problem. A user waiting on a
|
||||||
val priceIndependent = ownership.ownsAnything || grace != null
|
// pending payment is in the same position — the card is their answer, and both offers are
|
||||||
|
// locked anyway, so a price failure must not replace it with an error screen.
|
||||||
|
val priceIndependent = ownership.ownsAnything || grace != null || current.pendingSkus.isNotEmpty()
|
||||||
|
|
||||||
val done = queries as? SkuQueries.Done
|
val done = queries as? SkuQueries.Done
|
||||||
if (done == null) {
|
if (done == null) {
|
||||||
@@ -258,6 +261,7 @@ class UpgradeViewModel @Inject constructor(
|
|||||||
ownership = ownership,
|
ownership = ownership,
|
||||||
grace = grace,
|
grace = grace,
|
||||||
wasPreviouslyPro = wasEverPro && !current.isPro,
|
wasPreviouslyPro = wasEverPro && !current.isPro,
|
||||||
|
hasPendingPurchase = current.toPendingFlag(),
|
||||||
// This ViewModel's own action wins; otherwise a launch started elsewhere (previous VM
|
// This ViewModel's own action wins; otherwise a launch started elsewhere (previous VM
|
||||||
// instance, e.g. across a rotation — the launch lives on AppScope) or the repo's
|
// instance, e.g. across a rotation — the launch lives on AppScope) or the repo's
|
||||||
// invisible already-owned auto-restore still pauses the entitlement actions here.
|
// invisible already-owned auto-restore still pauses the entitlement actions here.
|
||||||
@@ -303,44 +307,78 @@ class UpgradeViewModel @Inject constructor(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Outcome of the pre-purchase check with Play. Both purchase paths share it: they buy
|
||||||
|
// alternatives of the same entitlement from the same account, so a check only one of them runs
|
||||||
|
// is exactly how a double charge slips through. [Blocked] means the user was already told why.
|
||||||
|
private sealed interface PurchaseGate {
|
||||||
|
data class Clear(val info: UpgradeRepoGplay.Info) : PurchaseGate
|
||||||
|
data object Blocked : PurchaseGate
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fails closed: no fresh, complete answer from Play (error, timeout) means no purchase. Bounded,
|
||||||
|
// because the repo waits for a healthy connection indefinitely and a tap must not park the
|
||||||
|
// single-flight guard through an outage.
|
||||||
|
private suspend fun runPurchaseGate(): PurchaseGate {
|
||||||
|
val info = try {
|
||||||
|
withTimeoutOrNull(VERIFY_TIMEOUT_MS) { upgradeRepo.verifyPurchaseStateNow() }
|
||||||
|
} catch (e: CancellationException) {
|
||||||
|
throw e
|
||||||
|
} catch (e: Exception) {
|
||||||
|
log(TAG, WARN) { "Purchase verification errored: ${e.asLog()}" }
|
||||||
|
errorEvents.tryEmit(e)
|
||||||
|
return PurchaseGate.Blocked
|
||||||
|
}
|
||||||
|
if (info == null) {
|
||||||
|
log(TAG, WARN) { "Purchase verification timed out" }
|
||||||
|
events.tryEmit(UpgradeEvents.PurchaseCheckFailed)
|
||||||
|
return PurchaseGate.Blocked
|
||||||
|
}
|
||||||
|
if (info.pendingSkus.isNotEmpty()) {
|
||||||
|
// Play rejects a purchase while it is still processing a payment for this account, and
|
||||||
|
// the alternative product would charge twice for the same features.
|
||||||
|
log(TAG, INFO) { "Purchase blocked: a payment is still pending" }
|
||||||
|
events.tryEmit(UpgradeEvents.PurchasePending)
|
||||||
|
return PurchaseGate.Blocked
|
||||||
|
}
|
||||||
|
return PurchaseGate.Clear(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A launch that failed on a pending payment is not an error the user can act on: it gets the
|
||||||
|
// informational dialog instead of the already-owned copy and its restore tips.
|
||||||
|
private fun onLaunchError(error: Throwable) {
|
||||||
|
if (error is PendingPurchaseBillingException) {
|
||||||
|
events.tryEmit(UpgradeEvents.PurchasePending)
|
||||||
|
} else {
|
||||||
|
errorEvents.tryEmit(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onGoIap(activity: Activity) {
|
fun onGoIap(activity: Activity) {
|
||||||
log(TAG) { "onGoIap($activity)" }
|
log(TAG) { "onGoIap($activity)" }
|
||||||
launch {
|
launch {
|
||||||
// Single-flight: repeated taps must not stack verifications or billing launches.
|
// Single-flight: repeated taps must not stack verifications or billing launches.
|
||||||
if (!acquireOp(BusyOp.IAP)) return@launch
|
if (!acquireOp(BusyOp.IAP)) return@launch
|
||||||
try {
|
try {
|
||||||
// Hard gate against double-billing: verify against a FRESH SUBS-only query — the
|
val gate = runPurchaseGate()
|
||||||
// replayed upgradeInfo can be stale or built from partial results. Fails closed:
|
if (gate !is PurchaseGate.Clear) return@launch
|
||||||
// no verified "not set to renew" (or no sub at all), no one-time purchase.
|
// Hard gate against double-billing, against the FRESH result — the replayed
|
||||||
val subscriptions = try {
|
// upgradeInfo can be stale or built from partial results. Asked of the RAW
|
||||||
withTimeoutOrNull(VERIFY_TIMEOUT_MS) { upgradeRepo.queryCurrentSubscriptions() }
|
// purchases (see Info.hasAutoRenewingSubscription), never of the mapped upgrades:
|
||||||
} catch (e: CancellationException) {
|
// a renewing subscription with an unknown or legacy product ID must block the
|
||||||
throw e
|
// one-time purchase too, or the user pays for Pro twice.
|
||||||
} catch (e: Exception) {
|
if (gate.info.hasAutoRenewingSubscription) {
|
||||||
log(TAG, WARN) { "Subscription verification errored: ${e.asLog()}" }
|
log(TAG, INFO) { "IAP purchase blocked: subscription is still set to renew" }
|
||||||
errorEvents.tryEmit(e)
|
events.tryEmit(UpgradeEvents.SubscriptionStillRenewing)
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
when {
|
// Suspends until the Play sheet launch resolved, so the single-flight guard covers
|
||||||
subscriptions == null -> {
|
// the whole tap-to-sheet window, not just the verification.
|
||||||
log(TAG, WARN) { "Subscription verification timed out" }
|
upgradeRepo.launchBillingFlowNow(
|
||||||
events.tryEmit(UpgradeEvents.SubscriptionCheckFailed)
|
activity,
|
||||||
}
|
OurSku.Iap.PRO_UPGRADE,
|
||||||
|
null,
|
||||||
subscriptions.any { it.isAutoRenewing } -> {
|
onError = ::onLaunchError,
|
||||||
log(TAG, INFO) { "IAP purchase blocked: subscription is still set to renew" }
|
)
|
||||||
events.tryEmit(UpgradeEvents.SubscriptionStillRenewing)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Suspends until the Play sheet launch resolved, so the single-flight guard
|
|
||||||
// covers the whole tap-to-sheet window, not just the verification.
|
|
||||||
else -> upgradeRepo.launchBillingFlowNow(
|
|
||||||
activity,
|
|
||||||
OurSku.Iap.PRO_UPGRADE,
|
|
||||||
null,
|
|
||||||
onError = errorEvents::tryEmit,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
activeOp.value = null
|
activeOp.value = null
|
||||||
}
|
}
|
||||||
@@ -361,6 +399,32 @@ class UpgradeViewModel @Inject constructor(
|
|||||||
launch {
|
launch {
|
||||||
if (!acquireOp(BusyOp.SUBSCRIPTION)) return@launch
|
if (!acquireOp(BusyOp.SUBSCRIPTION)) return@launch
|
||||||
try {
|
try {
|
||||||
|
// Same fresh check as the one-time path: a pending payment (for either product)
|
||||||
|
// must block this launch too — Play would reject it, or bill it on top.
|
||||||
|
val gate = runPurchaseGate()
|
||||||
|
if (gate !is PurchaseGate.Clear) return@launch
|
||||||
|
// The reactive UI can be stale (the purchase was made on another device), and Play
|
||||||
|
// happily sells the subscription alongside an owned one-time purchase — the user
|
||||||
|
// would pay for Pro twice. The strict refresh already committed into the shared
|
||||||
|
// billing data, so the screen re-renders to the ownership state, and the
|
||||||
|
// restore-success toast explains why nothing launched. Deliberately the MAPPED
|
||||||
|
// upgrades, not isPro: grace users (mapped upgrades empty) may legitimately
|
||||||
|
// re-purchase.
|
||||||
|
if (gate.info.upgrades.isNotEmpty()) {
|
||||||
|
log(TAG, INFO) { "Subscription purchase blocked: fresh check found an owned upgrade" }
|
||||||
|
events.tryEmit(UpgradeEvents.RestoreSucceeded)
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
// Same breadth as the one-time path's renewal guard: an auto-renewing subscription
|
||||||
|
// with an unknown or legacy product ID (which maps to zero upgrades, so the block
|
||||||
|
// above passed) must still block a new subscription — two renewing subscriptions
|
||||||
|
// for the same features is the same double-billing. Reuses the existing
|
||||||
|
// manage-subscription dialog.
|
||||||
|
if (gate.info.hasAutoRenewingSubscription) {
|
||||||
|
log(TAG, INFO) { "Subscription purchase blocked: another subscription is still set to renew" }
|
||||||
|
events.tryEmit(UpgradeEvents.SubscriptionStillRenewing)
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
// launchBillingFlowNow suspends until the launch resolved, so the guard covers the
|
// launchBillingFlowNow suspends until the launch resolved, so the guard covers the
|
||||||
// whole tap-to-sheet window. The flow itself still runs on AppScope, so closing the
|
// whole tap-to-sheet window. The flow itself still runs on AppScope, so closing the
|
||||||
// screen mid-launch doesn't abort the purchase.
|
// screen mid-launch doesn't abort the purchase.
|
||||||
@@ -368,7 +432,7 @@ class UpgradeViewModel @Inject constructor(
|
|||||||
activity,
|
activity,
|
||||||
OurSku.Sub.PRO_UPGRADE,
|
OurSku.Sub.PRO_UPGRADE,
|
||||||
offer,
|
offer,
|
||||||
onError = errorEvents::tryEmit,
|
onError = ::onLaunchError,
|
||||||
)
|
)
|
||||||
} finally {
|
} finally {
|
||||||
activeOp.value = null
|
activeOp.value = null
|
||||||
@@ -432,6 +496,14 @@ class UpgradeViewModel @Inject constructor(
|
|||||||
events.tryEmit(UpgradeEvents.RestoreSucceeded)
|
events.tryEmit(UpgradeEvents.RestoreSucceeded)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
restored.info.pendingSkus.isNotEmpty() -> {
|
||||||
|
// Play answered and found the purchase — it just hasn't been paid for yet.
|
||||||
|
// RestoreFailed would send this user chasing account and support advice for
|
||||||
|
// something that resolves itself.
|
||||||
|
log(TAG, INFO) { "Restore found a purchase with a pending payment" }
|
||||||
|
events.tryEmit(UpgradeEvents.PurchasePending)
|
||||||
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
// Play answered and had nothing. Includes a grace-only result from a successful
|
// Play answered and had nothing. Includes a grace-only result from a successful
|
||||||
// EMPTY query: Pro may still be active, but the check really did complete, so
|
// EMPTY query: Pro may still be active, but the check really did complete, so
|
||||||
|
|||||||
@@ -1,31 +1,20 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="upgrades_gplay_unavailable_error">Google Play-dienste is nie beskikbaar nie.</string>
|
<string name="upgrades_gplay_unavailable_error">Google Play-dienste is nie beskikbaar nie.</string>
|
||||||
<string name="upgrades_no_purchases_found_check_account">Geen aankope gevind nie. Gebruik jy die regte rekening?</string>
|
|
||||||
<string name="upgrades_gplay_billing_error_label">Google Play-fout</string>
|
<string name="upgrades_gplay_billing_error_label">Google Play-fout</string>
|
||||||
<string name="upgrades_gplay_billing_error_description">Daar was \'n fout in Google Play. Probeer asseblief later weer of herbegin jou foon.\n\nFout: %s</string>
|
<string name="upgrades_gplay_billing_error_description">Daar was \'n fout in Google Play. Probeer asseblief later weer of herbegin jou foon.\n\nFout: %s</string>
|
||||||
<string name="upgrades_gplay_billing_result_error_label">Google Play-faktureringsfout</string>
|
|
||||||
<string name="upgrades_gplay_billing_result_error_description">Daar was \'n fout toe Google Play om jou aankoopbesonderhede gevra is. Maak die Google Play-kas skoon en herbegin jou foon.\n\nFout %s</string>
|
|
||||||
<string name="upgrades_gplay_already_owned_label">Reeds gekoop?</string>
|
<string name="upgrades_gplay_already_owned_label">Reeds gekoop?</string>
|
||||||
<string name="upgrades_gplay_already_owned_description">Google Play meld dat jy reeds hierdie opgradering besit, maar dit kon nie herstel word nie. Maak seker jy gebruik die Google-rekening waarmee jy gekoop het. Play Store-sinkronisasie kan tyd neem — probeer herbegin, maak die Google Play-kas skoon, of wag eenvoudig \'n rukkie.</string>
|
<string name="upgrades_gplay_already_owned_description">Google Play meld dat jy reeds hierdie opgradering besit, maar dit kon nie herstel word nie. Maak seker jy gebruik die Google-rekening waarmee jy gekoop het. Play Store-sinkronisasie kan tyd neem — probeer herbegin, maak die Google Play-kas skoon, of wag eenvoudig \'n rukkie.</string>
|
||||||
<string name="upgrade_restore_action">Herstel aankoop</string>
|
|
||||||
<string name="upgrade_badge_label">Pro</string>
|
<string name="upgrade_badge_label">Pro</string>
|
||||||
<!-- %1$s is the full localized brand ("CAPod Pro", composed from the app name + postfix) — translate the sentence around it, keep the placeholder. -->
|
<!-- %1$s is the full localized brand ("CAPod Pro", composed from the app name + postfix) — translate the sentence around it, keep the placeholder. -->
|
||||||
<string name="upgrade_screen_title_template">Kry %1$s</string>
|
<string name="upgrade_screen_title_template">Kry %1$s</string>
|
||||||
<string name="upgrade_preamble">CAPod word deur een persoon ontwikkel. Opgradering ontsluit ekstra kenmerke en help om die toepassing lewend te hou.</string>
|
<string name="upgrade_preamble">CAPod word deur een persoon ontwikkel. Opgradering ontsluit ekstra kenmerke en help om die toepassing lewend te hou.</string>
|
||||||
<string name="upgrade_screen_options_description">Dieselfde kenmerke, verskillende pryse. Die intekening sluit \'n gratis proeftydperk in en kan te eniger tyd gekanselleer word.</string>
|
|
||||||
<string name="upgrade_screen_options_description_no_trial">Dieselfde kenmerke, verskillende pryse. Die intekening kan te eniger tyd gekanselleer word.</string>
|
|
||||||
<string name="upgrade_screen_subscription_trial_action">Begin gratis proeftydperk</string>
|
<string name="upgrade_screen_subscription_trial_action">Begin gratis proeftydperk</string>
|
||||||
<string name="upgrade_screen_subscription_action">Teken jaarliks in</string>
|
<string name="upgrade_screen_subscription_action">Teken jaarliks in</string>
|
||||||
<string name="upgrade_screen_subscription_action_hint">%s/jaar</string>
|
|
||||||
<string name="upgrade_screen_iap_action">Koop eenmalig</string>
|
<string name="upgrade_screen_iap_action">Koop eenmalig</string>
|
||||||
<string name="upgrade_screen_iap_action_hint">Eenmalige aankoop: %s</string>
|
|
||||||
<string name="upgrade_screen_restore_purchase_action">Herstel aankoop</string>
|
<string name="upgrade_screen_restore_purchase_action">Herstel aankoop</string>
|
||||||
<string name="upgrade_screen_restore_purchase_message">Geen aankope gevind nie. Gebruik jy die regte rekening?</string>
|
|
||||||
<string name="upgrade_screen_restore_troubleshooting_msg">As jy onlangs gekoop het, kan dit \'n rukkie neem vir Google Play om te sinkroniseer.</string>
|
|
||||||
<string name="upgrade_screen_restore_sync_patience_hint">Probeer weer oor \'n paar minute as jou aankoop nie verskyn nie.</string>
|
<string name="upgrade_screen_restore_sync_patience_hint">Probeer weer oor \'n paar minute as jou aankoop nie verskyn nie.</string>
|
||||||
<string name="upgrade_screen_restore_multiaccount_hint">Maak seker jy is aangemeld met dieselfde Google-rekening wat vir die aankoop gebruik is.</string>
|
<string name="upgrade_screen_restore_multiaccount_hint">Maak seker jy is aangemeld met dieselfde Google-rekening wat vir die aankoop gebruik is.</string>
|
||||||
<string name="upgrade_screen_restore_webinstall_hint">Veelvuldige rekeninge kan Google Play verwar. Deur die toepassing via die Google Play-webwerf te installeer, word die assosiasie met \'n spesifieke rekening afgedwing.</string>
|
|
||||||
<string name="upgrade_screen_restore_banner_title">Reeds Pro gekoop?</string>
|
<string name="upgrade_screen_restore_banner_title">Reeds Pro gekoop?</string>
|
||||||
<string name="upgrade_screen_restore_banner_body">Dit lyk asof jy voorheen op hierdie toestel na Pro opgegradeer het. Herstel jou aankoop om dit weer te ontsluit.</string>
|
<string name="upgrade_screen_restore_banner_body">Dit lyk asof jy voorheen op hierdie toestel na Pro opgegradeer het. Herstel jou aankoop om dit weer te ontsluit.</string>
|
||||||
<string name="upgrade_screen_restore_success_message">Aankoop herstel.</string>
|
<string name="upgrade_screen_restore_success_message">Aankoop herstel.</string>
|
||||||
@@ -34,7 +23,6 @@
|
|||||||
<string name="upgrade_screen_owned_hero_title">Jy het CAPod Pro!</string>
|
<string name="upgrade_screen_owned_hero_title">Jy het CAPod Pro!</string>
|
||||||
<string name="upgrade_screen_owned_hero_sub_body">Ontsluit deur jou intekening. Dankie dat jy CAPod ondersteun!</string>
|
<string name="upgrade_screen_owned_hero_sub_body">Ontsluit deur jou intekening. Dankie dat jy CAPod ondersteun!</string>
|
||||||
<string name="upgrade_screen_owned_hero_iap_body">Ontsluit deur jou eenmalige aankoop. Dankie dat jy CAPod ondersteun!</string>
|
<string name="upgrade_screen_owned_hero_iap_body">Ontsluit deur jou eenmalige aankoop. Dankie dat jy CAPod ondersteun!</string>
|
||||||
<string name="upgrade_screen_owned_sub_title">Jaarlikse intekening</string>
|
|
||||||
<string name="upgrade_screen_owned_sub_renewing_body">Jou intekening is aktief en gestel om te hernu. Fakturering word deur Google Play bestuur.</string>
|
<string name="upgrade_screen_owned_sub_renewing_body">Jou intekening is aktief en gestel om te hernu. Fakturering word deur Google Play bestuur.</string>
|
||||||
<string name="upgrade_screen_owned_sub_not_renewing_body">Jou intekening is aktief, maar nie gestel om te hernu nie. Pro bly beskikbaar totdat die huidige tydperk eindig.</string>
|
<string name="upgrade_screen_owned_sub_not_renewing_body">Jou intekening is aktief, maar nie gestel om te hernu nie. Pro bly beskikbaar totdat die huidige tydperk eindig.</string>
|
||||||
<string name="upgrade_screen_owned_iap_title">Eenmalige aankoop</string>
|
<string name="upgrade_screen_owned_iap_title">Eenmalige aankoop</string>
|
||||||
@@ -46,8 +34,10 @@
|
|||||||
<string name="upgrade_screen_owned_iap_purchase_note">Dit is \'n aparte aankoop — dit kanselleer of vergoed nie jou intekening nie. Gebruik dieselfde Google-rekening.</string>
|
<string name="upgrade_screen_owned_iap_purchase_note">Dit is \'n aparte aankoop — dit kanselleer of vergoed nie jou intekening nie. Gebruik dieselfde Google-rekening.</string>
|
||||||
<string name="upgrade_screen_sub_still_renewing_title">Intekening steeds aktief</string>
|
<string name="upgrade_screen_sub_still_renewing_title">Intekening steeds aktief</string>
|
||||||
<string name="upgrade_screen_sub_still_renewing_message">Jou intekening is steeds gestel om te hernu. Kanselleer dit eers in Google Play, en wissel dan na die eenmalige aankoop. Pas gekanselleer? Gee Google Play \'n oomblik en probeer weer.</string>
|
<string name="upgrade_screen_sub_still_renewing_message">Jou intekening is steeds gestel om te hernu. Kanselleer dit eers in Google Play, en wissel dan na die eenmalige aankoop. Pas gekanselleer? Gee Google Play \'n oomblik en probeer weer.</string>
|
||||||
<string name="upgrade_screen_sub_check_failed_title">Intekeningkontrole het misluk</string>
|
<string name="upgrade_screen_purchase_check_failed_message">Kon nie jou aankope by Google Play nagaan nie. Probeer weer oor \'n oomblik om \'n dubbele aankoop te vermy.</string>
|
||||||
<string name="upgrade_screen_sub_check_failed_message">Kon nie jou intekeningstatus by Google Play nagaan nie. Probeer binnekort weer om \'n dubbele aankoop te vermy.</string>
|
<string name="upgrade_screen_pending_card_title">Betaling hangende</string>
|
||||||
|
<string name="upgrade_screen_pending_card_body">Google Play verwerk steeds jou betaling. Pro word outomaties ontsluit sodra die betaling deurgaan. Sommige betaalmetodes kan \'n rukkie neem. Jy hoef verder niks te doen nie.</string>
|
||||||
|
<string name="upgrade_screen_pending_dialog_message">Google Play het \'n aankoop met \'n hangende betaling gevind en verwerk dit steeds. Pro word outomaties ontsluit sodra die betaling deurgaan.</string>
|
||||||
<string name="upgrade_screen_grace_title">Jou aankoop word bevestig</string>
|
<string name="upgrade_screen_grace_title">Jou aankoop word bevestig</string>
|
||||||
<string name="upgrade_screen_grace_body_short">Google Play het jou aankoop nog nie bevestig nie. Pro is steeds aktief — geen aksie nodig nie.</string>
|
<string name="upgrade_screen_grace_body_short">Google Play het jou aankoop nog nie bevestig nie. Pro is steeds aktief — geen aksie nodig nie.</string>
|
||||||
<string name="upgrade_screen_grace_body">Google Play het jou aankoop al \'n rukkie nie bevestig nie. Pro is steeds aktief. Maak seker jy is aanlyn en aangemeld met die Google-rekening wat vir die aankoop gebruik is, en probeer dan herstel.</string>
|
<string name="upgrade_screen_grace_body">Google Play het jou aankoop al \'n rukkie nie bevestig nie. Pro is steeds aktief. Maak seker jy is aanlyn en aangemeld met die Google-rekening wat vir die aankoop gebruik is, en probeer dan herstel.</string>
|
||||||
@@ -66,7 +56,6 @@
|
|||||||
<string name="upgrade_screen_restore_checked_message">CAPod het Google Play nou-nou gekontroleer, maar geen Pro-aankoop kon bevestig word vir die rekening wat Google Play vir hierdie app gebruik nie.</string>
|
<string name="upgrade_screen_restore_checked_message">CAPod het Google Play nou-nou gekontroleer, maar geen Pro-aankoop kon bevestig word vir die rekening wat Google Play vir hierdie app gebruik nie.</string>
|
||||||
<string name="upgrade_screen_restore_contact_hint">Nog steeds vas? Neem kontak op met ondersteuning van die e-posadres wat die aankoop gemaak het en voeg jou Google Play-ordernommer by.</string>
|
<string name="upgrade_screen_restore_contact_hint">Nog steeds vas? Neem kontak op met ondersteuning van die e-posadres wat die aankoop gemaak het en voeg jou Google Play-ordernommer by.</string>
|
||||||
<string name="upgrade_screen_contact_support_action">Neem kontak op met ondersteuning</string>
|
<string name="upgrade_screen_contact_support_action">Neem kontak op met ondersteuning</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod Pro</string>
|
|
||||||
<string name="settings_upgrade_status_description">Jou upgrade- en aankoopstatus.</string>
|
<string name="settings_upgrade_status_description">Jou upgrade- en aankoopstatus.</string>
|
||||||
<string name="upgrades_gplay_unavailable_error_description">CAPod kan nie aan Google Play koppel nie. Is Google Play geïnstalleer en opgedateer? Is jou Google-rekening aangemeld? Probeer om die kas van die Google Play-toepassing skoon te maak en jou toestel herlaai.</string>
|
<string name="upgrades_gplay_unavailable_error_description">CAPod kan nie aan Google Play koppel nie. Is Google Play geïnstalleer en opgedateer? Is jou Google-rekening aangemeld? Probeer om die kas van die Google Play-toepassing skoon te maak en jou toestel herlaai.</string>
|
||||||
<!-- Toast shown when the "Google Play" button of an error dialog can't open Google Play's app info, e.g. Google Play is missing or blocked on this device. "Google Play" is a brand name, keep it untranslated. -->
|
<!-- Toast shown when the "Google Play" button of an error dialog can't open Google Play's app info, e.g. Google Play is missing or blocked on this device. "Google Play" is a brand name, keep it untranslated. -->
|
||||||
|
|||||||
@@ -1,31 +1,20 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="upgrades_gplay_unavailable_error">የGoogle Play አገልግሎቶች አይገኙም።</string>
|
<string name="upgrades_gplay_unavailable_error">የGoogle Play አገልግሎቶች አይገኙም።</string>
|
||||||
<string name="upgrades_no_purchases_found_check_account">ምንም ግዢዎች አልተገኙም። ትክክለኛውን መለያ እየተጠቀሙ ነው?</string>
|
|
||||||
<string name="upgrades_gplay_billing_error_label">የGoogle Play ስህተት</string>
|
<string name="upgrades_gplay_billing_error_label">የGoogle Play ስህተት</string>
|
||||||
<string name="upgrades_gplay_billing_error_description">በGoogle Play ላይ ስህተት ነበር። እባክዎ ቆይተው ይሞክሩ ወይም ስልክዎን እንደገና ያስጀምሩ።\n\nስህተት: %s</string>
|
<string name="upgrades_gplay_billing_error_description">በGoogle Play ላይ ስህተት ነበር። እባክዎ ቆይተው ይሞክሩ ወይም ስልክዎን እንደገና ያስጀምሩ።\n\nስህተት: %s</string>
|
||||||
<string name="upgrades_gplay_billing_result_error_label">የGoogle Play ክፍያ ስህተት</string>
|
|
||||||
<string name="upgrades_gplay_billing_result_error_description">Google Play የግዢ ዝርዝሮችዎን ሲጠይቅ ስህተት ነበር። የGoogle Play መሸጎጫውን ያጽዱ እና ስልክዎን እንደገና ያስጀምሩ።\n\nስህተት %s</string>
|
|
||||||
<string name="upgrades_gplay_already_owned_label">አስቀድመው ገዝተዋል?</string>
|
<string name="upgrades_gplay_already_owned_label">አስቀድመው ገዝተዋል?</string>
|
||||||
<string name="upgrades_gplay_already_owned_description">Google Play ይህን ማሻሻያ አስቀድመው እንደያዙ ዘግቧል፣ ነገር ግን መመለስ አልተቻለም። በገዙበት የGoogle መለያ እየተጠቀሙ መሆኑን ያረጋግጡ። የPlay Store ማመሳሰል ጊዜ ሊወስድ ይችላል — እንደገና ለማስጀመር፣ የGoogle Play መሸጎጫን ለማጽዳት ወይም በቀላሉ ለመጠበቅ ይሞክሩ።</string>
|
<string name="upgrades_gplay_already_owned_description">Google Play ይህን ማሻሻያ አስቀድመው እንደያዙ ዘግቧል፣ ነገር ግን መመለስ አልተቻለም። በገዙበት የGoogle መለያ እየተጠቀሙ መሆኑን ያረጋግጡ። የPlay Store ማመሳሰል ጊዜ ሊወስድ ይችላል — እንደገና ለማስጀመር፣ የGoogle Play መሸጎጫን ለማጽዳት ወይም በቀላሉ ለመጠበቅ ይሞክሩ።</string>
|
||||||
<string name="upgrade_restore_action">ግዢን ወደነበረበት መልስ</string>
|
|
||||||
<string name="upgrade_badge_label">Pro</string>
|
<string name="upgrade_badge_label">Pro</string>
|
||||||
<!-- %1$s is the full localized brand ("CAPod Pro", composed from the app name + postfix) — translate the sentence around it, keep the placeholder. -->
|
<!-- %1$s is the full localized brand ("CAPod Pro", composed from the app name + postfix) — translate the sentence around it, keep the placeholder. -->
|
||||||
<string name="upgrade_screen_title_template">%1$s ያግኑ</string>
|
<string name="upgrade_screen_title_template">%1$s ያግኑ</string>
|
||||||
<string name="upgrade_preamble">CAPod የሚዘጋጀው በአንድ ሰው ብቻ ነው። ማሻሻል ተጨማሪ ባህሪያትን ይከፍታል እንዲሁም መተግበሪያውን ሕያው ለማድረግ ይረዳል።</string>
|
<string name="upgrade_preamble">CAPod የሚዘጋጀው በአንድ ሰው ብቻ ነው። ማሻሻል ተጨማሪ ባህሪያትን ይከፍታል እንዲሁም መተግበሪያውን ሕያው ለማድረግ ይረዳል።</string>
|
||||||
<string name="upgrade_screen_options_description">ተመሳሳይ ባህሪያት፣ የተለያየ ዋጋ አሰጣጥ። ምዝገባው ነጻ የሙከራ ጊዜ ያካትታል እና በማንኛውም ጊዜ ሊሰረዝ ይችላል።</string>
|
|
||||||
<string name="upgrade_screen_options_description_no_trial">ተመሳሳይ ባህሪያት፣ የተለያየ ዋጋ አሰጣጥ። ምዝገባው በማንኛውም ጊዜ ሊሰረዝ ይችላል።</string>
|
|
||||||
<string name="upgrade_screen_subscription_trial_action">ነጻ ሙከራ ጀምር</string>
|
<string name="upgrade_screen_subscription_trial_action">ነጻ ሙከራ ጀምር</string>
|
||||||
<string name="upgrade_screen_subscription_action">በዓመት ይመዝገቡ</string>
|
<string name="upgrade_screen_subscription_action">በዓመት ይመዝገቡ</string>
|
||||||
<string name="upgrade_screen_subscription_action_hint">%s/ዓመት</string>
|
|
||||||
<string name="upgrade_screen_iap_action">አንዴ ይግዙ</string>
|
<string name="upgrade_screen_iap_action">አንዴ ይግዙ</string>
|
||||||
<string name="upgrade_screen_iap_action_hint">የአንድ ጊዜ ግዢ፦ %s</string>
|
|
||||||
<string name="upgrade_screen_restore_purchase_action">ግዢን ወደነበረበት መልስ</string>
|
<string name="upgrade_screen_restore_purchase_action">ግዢን ወደነበረበት መልስ</string>
|
||||||
<string name="upgrade_screen_restore_purchase_message">ምንም ግዢዎች አልተገኙም። ትክክለኛውን መለያ እየተጠቀሙ ነው?</string>
|
|
||||||
<string name="upgrade_screen_restore_troubleshooting_msg">በቅርቡ ገዝተው ከሆነ፣ Google Play ለማመሳሰል ትንሽ ጊዜ ሊወስድ ይችላል።</string>
|
|
||||||
<string name="upgrade_screen_restore_sync_patience_hint">ግዢዎ ካልታየ በጥቂት ደቂቃዎች ውስጥ እንደገና ይሞክሩ።</string>
|
<string name="upgrade_screen_restore_sync_patience_hint">ግዢዎ ካልታየ በጥቂት ደቂቃዎች ውስጥ እንደገና ይሞክሩ።</string>
|
||||||
<string name="upgrade_screen_restore_multiaccount_hint">ለግዢው ጥቅም ላይ በዋለው ተመሳሳይ የGoogle መለያ መግባትዎን ያረጋግጡ።</string>
|
<string name="upgrade_screen_restore_multiaccount_hint">ለግዢው ጥቅም ላይ በዋለው ተመሳሳይ የGoogle መለያ መግባትዎን ያረጋግጡ።</string>
|
||||||
<string name="upgrade_screen_restore_webinstall_hint">ብዙ መለያዎች Google Playን ማምታታት ይችላሉ። መተግበሪያውን በGoogle Play ድርጣቢያ በኩል መጫን ከተወሰነ መለያ ጋር ግንኙነትን ያስገድዳል።</string>
|
|
||||||
<string name="upgrade_screen_restore_banner_title">Pro አስቀድመው ገዝተዋል?</string>
|
<string name="upgrade_screen_restore_banner_title">Pro አስቀድመው ገዝተዋል?</string>
|
||||||
<string name="upgrade_screen_restore_banner_body">ቀደም ሲል በዚህ መሣሪያ ወደ Pro እንዳሻሻሉ ይመስላል። እንደገና ለመክፈት ግዢዎን ይመልሱ።</string>
|
<string name="upgrade_screen_restore_banner_body">ቀደም ሲል በዚህ መሣሪያ ወደ Pro እንዳሻሻሉ ይመስላል። እንደገና ለመክፈት ግዢዎን ይመልሱ።</string>
|
||||||
<string name="upgrade_screen_restore_success_message">ግዢ ተመልሷል።</string>
|
<string name="upgrade_screen_restore_success_message">ግዢ ተመልሷል።</string>
|
||||||
@@ -34,7 +23,6 @@
|
|||||||
<string name="upgrade_screen_owned_hero_title">CAPod Pro አለዎት!</string>
|
<string name="upgrade_screen_owned_hero_title">CAPod Pro አለዎት!</string>
|
||||||
<string name="upgrade_screen_owned_hero_sub_body">በምዝገባዎ ተከፍቷል። CAPod ን ስለደገፉ እናመሰግናለን!</string>
|
<string name="upgrade_screen_owned_hero_sub_body">በምዝገባዎ ተከፍቷል። CAPod ን ስለደገፉ እናመሰግናለን!</string>
|
||||||
<string name="upgrade_screen_owned_hero_iap_body">በአንድ ጊዜ ግዢዎ ተከፍቷል። CAPod ን ስለደገፉ እናመሰግናለን!</string>
|
<string name="upgrade_screen_owned_hero_iap_body">በአንድ ጊዜ ግዢዎ ተከፍቷል። CAPod ን ስለደገፉ እናመሰግናለን!</string>
|
||||||
<string name="upgrade_screen_owned_sub_title">ዓመታዊ ምዝገባ</string>
|
|
||||||
<string name="upgrade_screen_owned_sub_renewing_body">ምዝገባዎ ንቁ ነው እና ለማደስ ተዘጋጅቶል። ክፍያ በGoogle Play ይተዳደራል።</string>
|
<string name="upgrade_screen_owned_sub_renewing_body">ምዝገባዎ ንቁ ነው እና ለማደስ ተዘጋጅቶል። ክፍያ በGoogle Play ይተዳደራል።</string>
|
||||||
<string name="upgrade_screen_owned_sub_not_renewing_body">ምዝገባዎ ንቁ ነው፣ ነገር ግን ለማደስ አልተዘጋጀም። አሑን ያለው ጊዜ እስክያለቅ ድረስ Pro ይገኛል።</string>
|
<string name="upgrade_screen_owned_sub_not_renewing_body">ምዝገባዎ ንቁ ነው፣ ነገር ግን ለማደስ አልተዘጋጀም። አሑን ያለው ጊዜ እስክያለቅ ድረስ Pro ይገኛል።</string>
|
||||||
<string name="upgrade_screen_owned_iap_title">አንድ ጊዜ ግዢ</string>
|
<string name="upgrade_screen_owned_iap_title">አንድ ጊዜ ግዢ</string>
|
||||||
@@ -46,8 +34,10 @@
|
|||||||
<string name="upgrade_screen_owned_iap_purchase_note">ይህ የተለየ ግዢ ነው — ምዝገባውን አይሰርዝም ወይም አይመልስም። ተመሳሳይ የGoogle መለያ ይጠቀሙ።</string>
|
<string name="upgrade_screen_owned_iap_purchase_note">ይህ የተለየ ግዢ ነው — ምዝገባውን አይሰርዝም ወይም አይመልስም። ተመሳሳይ የGoogle መለያ ይጠቀሙ።</string>
|
||||||
<string name="upgrade_screen_sub_still_renewing_title">ምዝገባ አሁነም ንቁ ነው</string>
|
<string name="upgrade_screen_sub_still_renewing_title">ምዝገባ አሁነም ንቁ ነው</string>
|
||||||
<string name="upgrade_screen_sub_still_renewing_message">ምዝገባዎ አሁንም ለማደስ ተዘጋጅቷል። መጀመሪያ በGoogle Play ውስጥ ይሰርዙት፣ ከዚያ ወደ አንድ ጊዜ ግዢ ይቀይሩ። አሁን ገና ሰርዘውታል? ለGoogle Play ትንሽ ጊዜ ይስጡ እና እንደገና ይሞክሩ።</string>
|
<string name="upgrade_screen_sub_still_renewing_message">ምዝገባዎ አሁንም ለማደስ ተዘጋጅቷል። መጀመሪያ በGoogle Play ውስጥ ይሰርዙት፣ ከዚያ ወደ አንድ ጊዜ ግዢ ይቀይሩ። አሁን ገና ሰርዘውታል? ለGoogle Play ትንሽ ጊዜ ይስጡ እና እንደገና ይሞክሩ።</string>
|
||||||
<string name="upgrade_screen_sub_check_failed_title">የምዝገባ ማረጋገጫ አልተሳካም</string>
|
<string name="upgrade_screen_purchase_check_failed_message">Google Play ውስጥ የእርስዎን ግዢ ማረጋገጥ አልተቻልም። ተደገመ ግዢ ለመቆጠብ ውሌት በኋላ ሞክሩት።</string>
|
||||||
<string name="upgrade_screen_sub_check_failed_message">የምዝገባ ሁኔታዎን ከGoogle Play ጋር ማረጋገጥ አልተቻለም። ድርብ ግዢን ለማስቀረት፣ ትንሽ ቆይተው እንደገና ይሞክሩ።</string>
|
<string name="upgrade_screen_pending_card_title">ክፍያ በሂደት ላይ</string>
|
||||||
|
<string name="upgrade_screen_pending_card_body">Google Play ክፍያዎን ሥራ ላይ ቀጥሏል። ክፍያው ከተጠናቀቀ በኋላ Pro ራሱ ይከፈታል። አንዳንድ ክፍያ ዘዴ ጊዜ ሊወስዱ ይችላሉ። ሌላ ምንም ሊያደርጉት የሚገቡ ነገር የለም።</string>
|
||||||
|
<string name="upgrade_screen_pending_dialog_message">Google Play ሥራ ያለበት ክፍያ ያለበት ግዢ አገኘ እና ሥራ ላይ ይገኛል። ክፍያው ከተጠናቀቀ በኋላ Pro ራሱ ይከፈታል።</string>
|
||||||
<string name="upgrade_screen_grace_title">ግዢዎን በማረጋገጥ ላይ</string>
|
<string name="upgrade_screen_grace_title">ግዢዎን በማረጋገጥ ላይ</string>
|
||||||
<string name="upgrade_screen_grace_body_short">Google Play ግዢዎን እስካሁን አላረጋገጠም። Pro አሁንም ንቁ ነው — ምንም እርምጃ አያስፈልግም።</string>
|
<string name="upgrade_screen_grace_body_short">Google Play ግዢዎን እስካሁን አላረጋገጠም። Pro አሁንም ንቁ ነው — ምንም እርምጃ አያስፈልግም።</string>
|
||||||
<string name="upgrade_screen_grace_body">Google Play ለተወሰነ ጊዜ ግዢዎን አላረጋገጠም። Pro አሁንም ንቁ ነው። መስመር ላይ መሆንዎን እና ለግዢው ጥቅም ላይ በዋለው የGoogle መለያ መግባትዎን ያረጋግጡ፣ ከዚያ ወደነበረበት ለመመለስ ይሞክሩ።</string>
|
<string name="upgrade_screen_grace_body">Google Play ለተወሰነ ጊዜ ግዢዎን አላረጋገጠም። Pro አሁንም ንቁ ነው። መስመር ላይ መሆንዎን እና ለግዢው ጥቅም ላይ በዋለው የGoogle መለያ መግባትዎን ያረጋግጡ፣ ከዚያ ወደነበረበት ለመመለስ ይሞክሩ።</string>
|
||||||
@@ -66,7 +56,6 @@
|
|||||||
<string name="upgrade_screen_restore_checked_message">CAPod አሁን Google Play አረጋገጠ፣ ነገር ግን Google Play ለዚህ መተግበሪያ ጥቅም ላይ ስለሚውለው መለያ Pro ግዢ ማረጋገጥ አልተቻለም።</string>
|
<string name="upgrade_screen_restore_checked_message">CAPod አሁን Google Play አረጋገጠ፣ ነገር ግን Google Play ለዚህ መተግበሪያ ጥቅም ላይ ስለሚውለው መለያ Pro ግዢ ማረጋገጥ አልተቻለም።</string>
|
||||||
<string name="upgrade_screen_restore_contact_hint">አሁንም ችግር ካጋጠመዎት? ግዢውን ያደረገው ኢሜይል በመጠቀም ድጋፍ ያግኙ እና Google Play ትዕዛዝ ቁጥርዎን ያካትቱ።</string>
|
<string name="upgrade_screen_restore_contact_hint">አሁንም ችግር ካጋጠመዎት? ግዢውን ያደረገው ኢሜይል በመጠቀም ድጋፍ ያግኙ እና Google Play ትዕዛዝ ቁጥርዎን ያካትቱ።</string>
|
||||||
<string name="upgrade_screen_contact_support_action">ድጋፍ ለማነጋገር</string>
|
<string name="upgrade_screen_contact_support_action">ድጋፍ ለማነጋገር</string>
|
||||||
<string name="settings_upgrade_status_label">CAPod Pro</string>
|
|
||||||
<string name="settings_upgrade_status_description">የእርስዎ ማሻሻያ እና ግዢ ሁኔታ።</string>
|
<string name="settings_upgrade_status_description">የእርስዎ ማሻሻያ እና ግዢ ሁኔታ።</string>
|
||||||
<string name="upgrades_gplay_unavailable_error_description">CAPod ከGoogle Play ጋር መገናኘት አይችልም። Google Play ተጭኖ እና ወቅታዊ ነው? የGoogle መለያዎ ገብቷል? የGoogle Play መተግበሪያ መሸጎጫ ማጥራት እና መሳሪያዎን እንደገና ማስጀመር ይሞክሩ።</string>
|
<string name="upgrades_gplay_unavailable_error_description">CAPod ከGoogle Play ጋር መገናኘት አይችልም። Google Play ተጭኖ እና ወቅታዊ ነው? የGoogle መለያዎ ገብቷል? የGoogle Play መተግበሪያ መሸጎጫ ማጥራት እና መሳሪያዎን እንደገና ማስጀመር ይሞክሩ።</string>
|
||||||
<!-- Toast shown when the "Google Play" button of an error dialog can't open Google Play's app info, e.g. Google Play is missing or blocked on this device. "Google Play" is a brand name, keep it untranslated. -->
|
<!-- Toast shown when the "Google Play" button of an error dialog can't open Google Play's app info, e.g. Google Play is missing or blocked on this device. "Google Play" is a brand name, keep it untranslated. -->
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user