diff --git a/apps/mobile/src/components/credits/credit-native-iap-owner.mounted.test.tsx b/apps/mobile/src/components/credits/credit-native-iap-owner.mounted.test.tsx index 85bb6fd65f3..c87702b3ded 100644 --- a/apps/mobile/src/components/credits/credit-native-iap-owner.mounted.test.tsx +++ b/apps/mobile/src/components/credits/credit-native-iap-owner.mounted.test.tsx @@ -789,7 +789,7 @@ describe('CreditNativeIapOwner', () => { expect(mockedIap.fetchProducts).toHaveBeenCalledTimes(2); }); - it('shows the store-unavailable copy when the second ask also fails', async () => { + it('shows the connection copy when the second ask also fails', async () => { mockedIap.connected = true; mockedIap.fetchProducts.mockRejectedValue(notReady); const { handle } = await mountOwner(); @@ -797,11 +797,42 @@ describe('CreditNativeIapOwner', () => { const failure = await loadPlayCatalog(handle).catch((error: unknown) => error); expect(failure).toBeInstanceOf(StoreCreditProductsError); - expect(failure).toMatchObject({ key: 'credits.noMatchingProductsPlay' }); + expect(failure).toMatchObject({ key: 'kiloPass.couldNotConnectToPlay' }); expect(mockedIap.reconnect).toHaveBeenCalledTimes(1); expect(mockedIap.fetchProducts).toHaveBeenCalledTimes(2); }); + it('does not ask again once the caller has given up on the store', async () => { + mockedIap.connected = true; + mockedIap.fetchProducts.mockRejectedValue(notReady); + const { handle } = await mountOwner(); + const controller = new AbortController(); + controller.abort(); + + await expect( + handle.value?.fetchStoreProducts(['credits_usd10'], { signal: controller.signal }) + ).rejects.toBe(notReady); + expect(mockedIap.reconnect).not.toHaveBeenCalled(); + expect(mockedIap.fetchProducts).toHaveBeenCalledTimes(1); + }); + + it('does not ask again when the caller gives up during the reconnect', async () => { + mockedIap.connected = true; + mockedIap.fetchProducts.mockRejectedValue(notReady); + const { handle } = await mountOwner(); + const controller = new AbortController(); + // eslint-disable-next-line eslint/require-await -- the abort is the behavior under test; reconnect answers at once + mockedIap.reconnect.mockImplementation(async () => { + controller.abort(); + return true; + }); + + await expect( + handle.value?.fetchStoreProducts(['credits_usd10'], { signal: controller.signal }) + ).rejects.toBe(notReady); + expect(mockedIap.fetchProducts).toHaveBeenCalledTimes(1); + }); + it('does not ask again when the reconnect fails', async () => { mockedIap.connected = true; mockedIap.reconnect.mockResolvedValue(false); diff --git a/apps/mobile/src/components/credits/credit-native-iap-owner.tsx b/apps/mobile/src/components/credits/credit-native-iap-owner.tsx index 347279131c7..99624f56bd4 100644 --- a/apps/mobile/src/components/credits/credit-native-iap-owner.tsx +++ b/apps/mobile/src/components/credits/credit-native-iap-owner.tsx @@ -24,6 +24,7 @@ import { currentAuthEpoch, isCurrentAuthEpoch } from '@/lib/auth/auth-epoch'; import { type StoreCreditProduct, type StoreCreditProductListing, + type StoreProductFetchOptions, } from '@/lib/credits/store-products'; import { getCreditStorefront } from '@/lib/credits/storefront'; import { fetchPendingStorePurchases } from '@/lib/iap/pending-store-purchases'; @@ -67,7 +68,10 @@ async function fetchCreditStoreProducts( export type CreditNativeIapContextValue = { connected: boolean; - fetchStoreProducts: (productSkus: string[]) => Promise; + fetchStoreProducts: ( + productSkus: string[], + options?: StoreProductFetchOptions + ) => Promise; /** * Restores the store connection after a failed initialization. expo-iap * removes its purchase-update listeners on that failure, and only the hook's @@ -565,12 +569,27 @@ export function CreditNativeIapOwner({ children }: { children: ReactNode }) { // once more, so one dropped connection is not reported as a store outage. A // reconnect that fails, or a second failure, reaches the loader, which shows // the store-unavailable copy. + // + // The ask once more is skipped once the caller's deadline has settled this + // call: the store SDK has no cancellation, so the first call can surface a + // stale failure long after the screen gave up, and a store that stayed + // silent for the whole deadline stays silent for a retry too. Checked before + // and after the reconnect, which is itself a store call. const fetchStoreProducts = useCallback( - async (productSkus: string[]): Promise => { + async ( + productSkus: string[], + options?: StoreProductFetchOptions + ): Promise => { + const signal = options?.signal; try { return await fetchCreditStoreProducts(productSkus); } catch (error) { - if (!isStoreNotReadyError(error) || !(await reconnectStore())) { + if ( + signal?.aborted || + !isStoreNotReadyError(error) || + !(await reconnectStore()) || + signal?.aborted + ) { throw error; } return fetchCreditStoreProducts(productSkus); diff --git a/apps/mobile/src/components/credits/credit-purchase-screen.mounted.test.tsx b/apps/mobile/src/components/credits/credit-purchase-screen.mounted.test.tsx index 6e5ed7687a3..b073e49d5a6 100644 --- a/apps/mobile/src/components/credits/credit-purchase-screen.mounted.test.tsx +++ b/apps/mobile/src/components/credits/credit-purchase-screen.mounted.test.tsx @@ -280,13 +280,18 @@ describe('CreditPurchaseScreen', () => { await waitFor(() => allText(renderer).includes('App Store products unavailable')); expect(packRows(renderer)).toHaveLength(4); - expect(allText(renderer)).toContain('No matching credit packs were returned by App Store.'); + expect(allText(renderer)).toContain( + 'Could not connect to the App Store. Check your connection and try again.' + ); // The iOS card names the App Store for both its title and its body; the // Google Play copy must never leak onto it. expect(allText(renderer)).not.toContain('Google Play products unavailable'); expect(allText(renderer)).not.toContain( - 'No matching credit packs were returned by Google Play.' + 'Could not connect to Google Play. Check your connection and try again.' ); + // A store failure is not a catalog claim: the no-match body belongs to a + // store that answered and priced no pack. + expect(allText(renderer)).not.toContain('No matching credit packs were returned by App Store.'); expect(allText(renderer)).toContain('Price unavailable'); // The store SDK's own wording never reaches the screen. expect(allText(renderer)).not.toContain('Failed to query product'); @@ -313,10 +318,60 @@ describe('CreditPurchaseScreen', () => { const { renderer, unmount } = await renderWithProviders(createElement(CreditPurchaseScreen)); await waitFor(() => allText(renderer).includes('Google Play products unavailable')); - expect(allText(renderer)).toContain('No matching credit packs were returned by Google Play.'); + expect(allText(renderer)).toContain( + 'Could not connect to Google Play. Check your connection and try again.' + ); // The App Store copy must never leak onto the Android card. expect(allText(renderer)).not.toContain('App Store products unavailable'); - expect(allText(renderer)).not.toContain('No matching credit packs were returned by App Store.'); + expect(allText(renderer)).not.toContain( + 'Could not connect to the App Store. Check your connection and try again.' + ); + expect(packRows(renderer)).toHaveLength(4); + unmount(); + }); + + it('timeout: a store that never answers shows the timeout copy, not a catalog claim', async () => { + mockedPlatform.OS = 'android'; + owner.fetchStoreProducts.mockImplementation( + // eslint-disable-next-line @typescript-eslint/promise-function-async -- the store never answers, which is the scenario under test + () => new Promise(() => undefined) + ); + vi.useFakeTimers(); + try { + const { renderer, unmount } = await renderWithProviders(createElement(CreditPurchaseScreen)); + // Let the mount reach the store call and arm the loader's deadline. + await settleTimers(() => owner.fetchStoreProducts.mock.calls.length === 1); + await act(async () => { + await vi.advanceTimersByTimeAsync(15_000); + }); + await settleTimers(() => allText(renderer).includes('Google Play products unavailable')); + + expect(allText(renderer)).toContain('Google Play products unavailable'); + expect(allText(renderer)).toContain("Google Play didn't respond in time. Try again."); + expect(allText(renderer)).not.toContain( + 'No matching credit packs were returned by Google Play.' + ); + expect(allText(renderer)).not.toContain( + 'Could not connect to Google Play. Check your connection and try again.' + ); + // The backend amounts stay on screen, unpriced, with a retry to offer. + expect(packRows(renderer)).toHaveLength(4); + expect(allText(renderer)).toContain('Price unavailable'); + unmount(); + } finally { + vi.useRealTimers(); + } + }); + + it('no match: a store that answers without pricing a pack keeps the catalog claim', async () => { + mockedPlatform.OS = 'android'; + owner.fetchStoreProducts.mockResolvedValue([{ id: 'credits_usd250', displayPrice: '$249.99' }]); + + const { renderer, unmount } = await renderWithProviders(createElement(CreditPurchaseScreen)); + await waitFor(() => allText(renderer).includes('Google Play products unavailable')); + + expect(allText(renderer)).toContain('No matching credit packs were returned by Google Play.'); + expect(allText(renderer)).not.toContain("Google Play didn't respond in time. Try again."); expect(packRows(renderer)).toHaveLength(4); unmount(); }); @@ -390,7 +445,9 @@ describe('CreditPurchaseScreen', () => { expect(owner.fetchStoreProducts.mock.calls.length).toBe(2); expect(packRows(renderer)).toHaveLength(4); expect(allText(renderer)).toContain('App Store products unavailable'); - expect(allText(renderer)).toContain('No matching credit packs were returned by App Store.'); + expect(allText(renderer)).toContain( + 'Could not connect to the App Store. Check your connection and try again.' + ); expect(allText(renderer)).toContain('Price unavailable'); expect(renderer.root.findAll(node => String(node.type) === 'Skeleton')).toHaveLength(0); // The button that started the retry stays on screen, busy and disabled. diff --git a/apps/mobile/src/i18n/locales/af.json b/apps/mobile/src/i18n/locales/af.json index c16699e311d..5461234e4d0 100644 --- a/apps/mobile/src/i18n/locales/af.json +++ b/apps/mobile/src/i18n/locales/af.json @@ -3725,6 +3725,8 @@ "empty": "Kredietpakkette is tans nie beskikbaar nie.", "noMatchingProducts": "Geen passende kredietpakkette is deur App Store terugbesorg nie.", "noMatchingProductsPlay": "Geen passende kredietpakkette is deur Google Play terugbesorg nie.", + "storeTimedOut": "App Store het nie betyds gereageer nie. Probeer weer.", + "storeTimedOutPlay": "Google Play het nie betyds gereageer nie. Probeer weer.", "purchaseOwnedByAnotherAccount": "Die krediete op hierdie Apple Account behoort aan 'n ander Kilo-rekening. Meld by daardie Kilo-rekening aan om dit te gebruik.", "purchaseOwnedByAnotherAccountPlay": "Die krediete op hierdie Google Play-rekening behoort aan 'n ander Kilo-rekening. Teken in by daardie Kilo-rekening om dit te gebruik." }, diff --git a/apps/mobile/src/i18n/locales/am.json b/apps/mobile/src/i18n/locales/am.json index 00eb9565979..03b096cd82d 100644 --- a/apps/mobile/src/i18n/locales/am.json +++ b/apps/mobile/src/i18n/locales/am.json @@ -3725,6 +3725,8 @@ "empty": "የክሬዲት ጥቅሎች አሁን አይገኙም።", "noMatchingProducts": "ከApp Store ምንም ተመሳሳይ የክሬዲት ጥቅሎች አልተመለሱም።", "noMatchingProductsPlay": "ከGoogle Play ምንም ተመሳሳይ የክሬዲት ጥቅሎች አልተመለሱም።", + "storeTimedOut": "App Store በወቅቱ አልሰራም። እንደገና ይሞክሩ።", + "storeTimedOutPlay": "Google Play በወቅቱ አልሰራም። እንደገና ይሞክሩ።", "purchaseOwnedByAnotherAccount": "በዚህ Apple Account ላይ ያለው ክሬዲት የሌላ የKilo መለያ ነው። እነሱን ለመጠቀም ወደዚያ የKilo መለያ ይግቡ።", "purchaseOwnedByAnotherAccountPlay": "በዚህ Google Play መለያ ላይ ያለው ክሬዲት የተለየ የKilo መለያ ነው። እነሱን ለመጠቀም ወደዚያ የKilo መለያ ይግቡ።" }, diff --git a/apps/mobile/src/i18n/locales/ar.json b/apps/mobile/src/i18n/locales/ar.json index 4a218f5d205..a3dae1bcf2d 100644 --- a/apps/mobile/src/i18n/locales/ar.json +++ b/apps/mobile/src/i18n/locales/ar.json @@ -3889,6 +3889,8 @@ "empty": "حزم الرصيد غير متاحة الآن.", "noMatchingProducts": "لم يُرجِع App Store أي حزم رصيد مطابقة.", "noMatchingProductsPlay": "لم يُرجِع Google Play أي حزم رصيد مطابقة.", + "storeTimedOut": "لم يستجب App Store في الوقت المناسب. إعادة المحاولة.", + "storeTimedOutPlay": "لم يستجب Google Play في الوقت المناسب. إعادة المحاولة.", "purchaseOwnedByAnotherAccount": "الرصيد على حساب Apple Account هذا يخص حساب Kilo آخر. سجّل الدخول إلى حساب Kilo ذلك لاستخدامه.", "purchaseOwnedByAnotherAccountPlay": "الرصيد على حساب Google Play هذا يخص حساب Kilo مختلف. سجّل الدخول إلى حساب Kilo ذلك لاستخدامه." }, diff --git a/apps/mobile/src/i18n/locales/az.json b/apps/mobile/src/i18n/locales/az.json index 5a9874d09f1..d0d757614f0 100644 --- a/apps/mobile/src/i18n/locales/az.json +++ b/apps/mobile/src/i18n/locales/az.json @@ -3725,6 +3725,8 @@ "empty": "Kredit paketləri hazırda əlçatan deyil.", "noMatchingProducts": "App Store tərəfindən uyğun kredit paketi qaytarılmadı.", "noMatchingProductsPlay": "Google Play tərəfindən uyğun kredit paketi qaytarılmadı.", + "storeTimedOut": "App Store vaxtında cavab vermədi. Yenidən cəhd et.", + "storeTimedOutPlay": "Google Play vaxtında cavab vermədi. Yenidən cəhd et.", "purchaseOwnedByAnotherAccount": "Bu Apple Account hesabındakı kreditlər başqa Kilo hesabına aiddir. Onlardan istifadə etmək üçün həmin Kilo hesabına daxil ol.", "purchaseOwnedByAnotherAccountPlay": "Bu Google Play hesabındakı kreditlər başqa Kilo hesabına aiddir. Onlardan istifadə etmək üçün həmin Kilo hesabına daxil olun." }, diff --git a/apps/mobile/src/i18n/locales/be.json b/apps/mobile/src/i18n/locales/be.json index c15776bc47d..434c0fa1b7f 100644 --- a/apps/mobile/src/i18n/locales/be.json +++ b/apps/mobile/src/i18n/locales/be.json @@ -3807,6 +3807,8 @@ "empty": "Наборы крэдытаў зараз недаступныя.", "noMatchingProducts": "App Store не вярнуў адпаведных набораў крэдытаў.", "noMatchingProductsPlay": "Google Play не вярнуў адпаведных набораў крэдытаў.", + "storeTimedOut": "App Store не адказаў своечасова. Паспрабаваць яшчэ раз.", + "storeTimedOutPlay": "Google Play не адказаў своечасова. Паспрабаваць яшчэ раз.", "purchaseOwnedByAnotherAccount": "Крэдыты на гэтым Apple Account належаць іншаму ўліковаму запісу Kilo. Увайдзіце ў той уліковы запіс Kilo, каб імі карыстацца.", "purchaseOwnedByAnotherAccountPlay": "Крэдыты на гэтым Google Play належаць іншаму ўліковаму запісу Kilo. Увайдзіце ў той уліковы запіс Kilo, каб імі карыстацца." }, diff --git a/apps/mobile/src/i18n/locales/bg.json b/apps/mobile/src/i18n/locales/bg.json index 4478392b6ac..8b107f45463 100644 --- a/apps/mobile/src/i18n/locales/bg.json +++ b/apps/mobile/src/i18n/locales/bg.json @@ -3725,6 +3725,8 @@ "empty": "Пакетите с кредити в момента не са налични.", "noMatchingProducts": "App Store не върна съвпадащи пакети с кредити.", "noMatchingProductsPlay": "Google Play не върна съвпадащи пакети с кредити.", + "storeTimedOut": "App Store не отговори навреме. Опитай отново.", + "storeTimedOutPlay": "Google Play не отговори навреме. Опитай отново.", "purchaseOwnedByAnotherAccount": "Кредитите в този Apple Account принадлежат на друг акаунт в Kilo. Влез в съответния акаунт в Kilo, за да ги използваш.", "purchaseOwnedByAnotherAccountPlay": "Кредитите на този Google Play акаунт принадлежат на друг Kilo акаунт. Влезте в този Kilo акаунт, за да ги използвате." }, diff --git a/apps/mobile/src/i18n/locales/bn.json b/apps/mobile/src/i18n/locales/bn.json index eea7720f685..7020573b83b 100644 --- a/apps/mobile/src/i18n/locales/bn.json +++ b/apps/mobile/src/i18n/locales/bn.json @@ -3725,6 +3725,8 @@ "empty": "ক্রেডিট প্যাক এখন পাওয়া যাচ্ছে না।", "noMatchingProducts": "App Store কোনো মিলে যাওয়া ক্রেডিট প্যাক ফেরত দেয়নি।", "noMatchingProductsPlay": "Google Play কোনো মিলে যাওয়া ক্রেডিট প্যাক ফেরত দেয়নি।", + "storeTimedOut": "App Store সময়মতো সাড়া দেয়নি। আবার চেষ্টা করুন।", + "storeTimedOutPlay": "Google Play সময়মতো সাড়া দেয়নি। আবার চেষ্টা করুন।", "purchaseOwnedByAnotherAccount": "এই Apple Account-এর ক্রেডিট অন্য একটি Kilo অ্যাকাউন্টের। সেগুলো ব্যবহার করতে সেই Kilo অ্যাকাউন্টে সাইন-ইন করুন।", "purchaseOwnedByAnotherAccountPlay": "এই Google Play অ্যাকাউন্টের ক্রেডিট একটি ভিন্ন Kilo অ্যাকাউন্টের। সেগুলো ব্যবহার করতে সেই Kilo অ্যাকাউন্টে সাইন ইন করুন।" }, diff --git a/apps/mobile/src/i18n/locales/bs.json b/apps/mobile/src/i18n/locales/bs.json index 8d142438d91..5eef6e4776f 100644 --- a/apps/mobile/src/i18n/locales/bs.json +++ b/apps/mobile/src/i18n/locales/bs.json @@ -3766,6 +3766,8 @@ "empty": "Paketi kredita trenutno nisu dostupni.", "noMatchingProducts": "App Store nije vratio odgovarajuće pakete kredita.", "noMatchingProductsPlay": "Google Play nije vratio odgovarajuće pakete kredita.", + "storeTimedOut": "App Store nije odgovorio na vrijeme. Pokušaj ponovo.", + "storeTimedOutPlay": "Google Play nije odgovorio na vrijeme. Pokušaj ponovo.", "purchaseOwnedByAnotherAccount": "Krediti na ovom računu Apple Account pripadaju drugom Kilo računu. Prijavi se na taj Kilo račun da ih koristiš.", "purchaseOwnedByAnotherAccountPlay": "Krediti na ovom Google Play nalogu pripadaju drugom Kilo nalogu. Prijavite se na taj Kilo nalog da biste ih koristili." }, diff --git a/apps/mobile/src/i18n/locales/ca.json b/apps/mobile/src/i18n/locales/ca.json index 50aa869598d..34496128444 100644 --- a/apps/mobile/src/i18n/locales/ca.json +++ b/apps/mobile/src/i18n/locales/ca.json @@ -3766,6 +3766,8 @@ "empty": "Els paquets de crèdits no estan disponibles ara mateix.", "noMatchingProducts": "L'App Store no ha retornat cap paquet de crèdits coincident.", "noMatchingProductsPlay": "Google Play no ha retornat cap paquet de crèdits coincident.", + "storeTimedOut": "L'App Store no ha respost a temps. Torna-ho a provar.", + "storeTimedOutPlay": "Google Play no ha respost a temps. Torna-ho a provar.", "purchaseOwnedByAnotherAccount": "Els crèdits d'aquest Apple Account pertanyen a un altre compte de Kilo. Inicia la sessió en aquell compte de Kilo per utilitzar-los.", "purchaseOwnedByAnotherAccountPlay": "Els crèdits d'aquest compte de Google Play pertanyen a un compte de Kilo diferent. Inicia la sessió en aquest compte de Kilo per utilitzar-los." }, diff --git a/apps/mobile/src/i18n/locales/ckb.json b/apps/mobile/src/i18n/locales/ckb.json index 3d3549619a0..848177816a6 100644 --- a/apps/mobile/src/i18n/locales/ckb.json +++ b/apps/mobile/src/i18n/locales/ckb.json @@ -3725,6 +3725,8 @@ "empty": "پاکێتەکانی کرێدیت ئێستا بەردەست نین.", "noMatchingProducts": "هیچ پاکێتی کرێدیتی گونجاوی لەلایەن App Storeەوە نەگەڕێندرایەوە.", "noMatchingProductsPlay": "هیچ پاکێتی کرێدیتی گونجاوی لەلایەن Google Playەوە نەگەڕێندرایەوە.", + "storeTimedOut": "App Store لە کاتی خۆیدا وەڵامی نەداوە. دووبارە هەوڵ بدەوە.", + "storeTimedOutPlay": "Google Play لە کاتی خۆیدا وەڵامی نەداوە. دووبارە هەوڵ بدەوە.", "purchaseOwnedByAnotherAccount": "کرێدیتەکانی سەر ئەم Apple Accountە هی هەژمارێکی تری Kiloیە. بچۆ ناو ئەو هەژمارەی Kilo بۆ بەکارهێنانیان.", "purchaseOwnedByAnotherAccountPlay": "کرێدیتەکانی سەر ئەم هەژمارەی Google Play سەر بە هەژمارەیەکی دیکەی Kilo یە. بچۆ ژوورەوە لەو هەژمارەی Kilo بۆ بەکارهێنانیان." }, diff --git a/apps/mobile/src/i18n/locales/cs.json b/apps/mobile/src/i18n/locales/cs.json index 3d875e74baa..a3e38758f9e 100644 --- a/apps/mobile/src/i18n/locales/cs.json +++ b/apps/mobile/src/i18n/locales/cs.json @@ -3807,6 +3807,8 @@ "empty": "Balíčky kreditů teď nejsou k dispozici.", "noMatchingProducts": "App Store nevrátil žádné odpovídající balíčky kreditů.", "noMatchingProductsPlay": "Google Play nevrátil žádné odpovídající balíčky kreditů.", + "storeTimedOut": "App Store neodpověděl včas. Zkusit znovu.", + "storeTimedOutPlay": "Google Play neodpověděl včas. Zkusit znovu.", "purchaseOwnedByAnotherAccount": "Kredity na tomto účtu Apple Account patří k jinému účtu Kilo. Chcete-li je použít, přihlaste se k příslušnému účtu Kilo.", "purchaseOwnedByAnotherAccountPlay": "Kredity na tomto účtu Google Play patří jinému účtu Kilo. Přihlaste se k tomuto účtu Kilo pro jejich použití." }, diff --git a/apps/mobile/src/i18n/locales/cy.json b/apps/mobile/src/i18n/locales/cy.json index 28e7298b798..c10927d2bf4 100644 --- a/apps/mobile/src/i18n/locales/cy.json +++ b/apps/mobile/src/i18n/locales/cy.json @@ -3889,6 +3889,8 @@ "empty": "Nid yw pecynnau credydau ar gael ar hyn o bryd.", "noMatchingProducts": "Ni ddychwelodd yr App Store unrhyw becynnau credydau cyfatebol.", "noMatchingProductsPlay": "Ni ddychwelodd Google Play unrhyw becynnau credydau cyfatebol.", + "storeTimedOut": "Ni ymatebodd yr App Store mewn amser. Rhoi cynnig eto.", + "storeTimedOutPlay": "Ni ymatebodd Google Play mewn amser. Rhoi cynnig eto.", "purchaseOwnedByAnotherAccount": "Mae'r credydau ar yr Apple Account hwn yn perthyn i gyfrif Kilo gwahanol. Mewngofnodwch i'r cyfrif Kilo hwnnw i'w defnyddio.", "purchaseOwnedByAnotherAccountPlay": "Mae'r credydau ar y cyfrif Google Play hwn yn perthyn i gyfrif Kilo gwahanol. Mewngofnodwch i'r cyfrif Kilo hwnnw i'w defnyddio." }, diff --git a/apps/mobile/src/i18n/locales/da.json b/apps/mobile/src/i18n/locales/da.json index 2c6b3a2cad7..d6765f6bf9a 100644 --- a/apps/mobile/src/i18n/locales/da.json +++ b/apps/mobile/src/i18n/locales/da.json @@ -3725,6 +3725,8 @@ "empty": "Kreditpakker er ikke tilgængelige lige nu.", "noMatchingProducts": "App Store returnerede ingen matchende kreditpakker.", "noMatchingProductsPlay": "Google Play returnerede ingen matchende kreditpakker.", + "storeTimedOut": "App Store svarede ikke i tide. Prøv igen.", + "storeTimedOutPlay": "Google Play svarede ikke i tide. Prøv igen.", "purchaseOwnedByAnotherAccount": "Kreditterne på denne Apple-konto tilhører en anden Kilo-konto. Log ind på den Kilo-konto for at bruge dem.", "purchaseOwnedByAnotherAccountPlay": "Kreditterne på denne Google Play-konto tilhører en anden Kilo-konto. Log ind på den Kilo-konto for at bruge dem." }, diff --git a/apps/mobile/src/i18n/locales/de.json b/apps/mobile/src/i18n/locales/de.json index e02e4330f28..0fdce795cd5 100644 --- a/apps/mobile/src/i18n/locales/de.json +++ b/apps/mobile/src/i18n/locales/de.json @@ -3725,6 +3725,8 @@ "empty": "Guthaben-Pakete sind derzeit nicht verfügbar.", "noMatchingProducts": "Der App Store hat keine passenden Guthaben-Pakete zurückgegeben.", "noMatchingProductsPlay": "Google Play hat keine passenden Guthaben-Pakete zurückgegeben.", + "storeTimedOut": "Der App Store hat nicht rechtzeitig geantwortet. Erneut versuchen.", + "storeTimedOutPlay": "Google Play hat nicht rechtzeitig geantwortet. Erneut versuchen.", "purchaseOwnedByAnotherAccount": "Das Guthaben dieses Apple Accounts gehört zu einem anderen Kilo-Konto. Melde dich bei dem zugehörigen Kilo-Konto an, um es zu nutzen.", "purchaseOwnedByAnotherAccountPlay": "Das Guthaben auf diesem Google-Konto gehört zu einem anderen Kilo-Konto. Melde dich bei diesem Kilo-Konto an, um es zu nutzen." }, diff --git a/apps/mobile/src/i18n/locales/el.json b/apps/mobile/src/i18n/locales/el.json index 4bc5fc50555..f40072c0bcf 100644 --- a/apps/mobile/src/i18n/locales/el.json +++ b/apps/mobile/src/i18n/locales/el.json @@ -3725,6 +3725,8 @@ "empty": "Τα πακέτα πιστώσεων δεν είναι διαθέσιμα αυτή τη στιγμή.", "noMatchingProducts": "Το App Store δεν επέστρεψε αντίστοιχα πακέτα πιστώσεων.", "noMatchingProductsPlay": "Το Google Play δεν επέστρεψε αντίστοιχα πακέτα πιστώσεων.", + "storeTimedOut": "Το App Store δεν αποκρίθηκε εγκαίρως. Νέα προσπάθεια.", + "storeTimedOutPlay": "Το Google Play δεν αποκρίθηκε εγκαίρως. Νέα προσπάθεια.", "purchaseOwnedByAnotherAccount": "Οι πιστώσεις σε αυτό το Apple Account ανήκουν σε διαφορετικό λογαριασμό Kilo. Συνδέσου σε εκείνον τον λογαριασμό Kilo για να τις χρησιμοποιήσεις.", "purchaseOwnedByAnotherAccountPlay": "Οι πιστώσεις σε αυτόν τον λογαριασμό Google Play ανήκουν σε διαφορετικό λογαριασμό Kilo. Συνδεθείτε σε αυτόν τον λογαριασμό Kilo για να τις χρησιμοποιήσετε." }, diff --git a/apps/mobile/src/i18n/locales/en.json b/apps/mobile/src/i18n/locales/en.json index 84de473f48e..bc050793a77 100644 --- a/apps/mobile/src/i18n/locales/en.json +++ b/apps/mobile/src/i18n/locales/en.json @@ -3789,6 +3789,8 @@ "empty": "Credit packs are unavailable right now.", "noMatchingProducts": "No matching credit packs were returned by App Store.", "noMatchingProductsPlay": "No matching credit packs were returned by Google Play.", + "storeTimedOut": "App Store didn't respond in time. Try again.", + "storeTimedOutPlay": "Google Play didn't respond in time. Try again.", "purchaseOwnedByAnotherAccount": "The credits on this Apple Account belong to a different Kilo account. Sign in to that Kilo account to use them.", "purchaseOwnedByAnotherAccountPlay": "The credits on this Google Play account belong to a different Kilo account. Sign in to that Kilo account to use them." }, diff --git a/apps/mobile/src/i18n/locales/es.json b/apps/mobile/src/i18n/locales/es.json index 97a36d8b438..b2cac3f96a6 100644 --- a/apps/mobile/src/i18n/locales/es.json +++ b/apps/mobile/src/i18n/locales/es.json @@ -3766,6 +3766,8 @@ "empty": "Los paquetes de créditos no están disponibles ahora mismo.", "noMatchingProducts": "La App Store no devolvió ningún paquete de créditos coincidente.", "noMatchingProductsPlay": "Google Play no devolvió ningún paquete de créditos coincidente.", + "storeTimedOut": "App Store no respondió a tiempo. Volver a intentarlo.", + "storeTimedOutPlay": "Google Play no respondió a tiempo. Volver a intentarlo.", "purchaseOwnedByAnotherAccount": "El crédito de esta cuenta de Apple pertenece a una cuenta de Kilo diferente. Inicia sesión en esa cuenta de Kilo para usarlo.", "purchaseOwnedByAnotherAccountPlay": "El crédito de esta cuenta de Google Play pertenece a una cuenta de Kilo diferente. Inicia sesión en esa cuenta de Kilo para usarlo." }, diff --git a/apps/mobile/src/i18n/locales/et.json b/apps/mobile/src/i18n/locales/et.json index 443cfc64b96..27cd2916e7e 100644 --- a/apps/mobile/src/i18n/locales/et.json +++ b/apps/mobile/src/i18n/locales/et.json @@ -3725,6 +3725,8 @@ "empty": "Krediidipaketid pole praegu saadaval.", "noMatchingProducts": "App Store ei tagastanud ühtegi sobivat krediidipaketti.", "noMatchingProductsPlay": "Google Play ei tagastanud ühtegi sobivat krediidipaketti.", + "storeTimedOut": "App Store ei vastanud õigeaegselt. Proovi uuesti.", + "storeTimedOutPlay": "Google Play ei vastanud õigeaegselt. Proovi uuesti.", "purchaseOwnedByAnotherAccount": "Selle Apple Accountiga seotud krediit kuulub teisele Kilo kontole. Selle kasutamiseks logi sisse vastavale Kilo kontole.", "purchaseOwnedByAnotherAccountPlay": "Selle Google Play kontoga seotud krediit kuulub teisele Kilo kontole. Selle kasutamiseks logi sisse sellesse Kilo kontosse." }, diff --git a/apps/mobile/src/i18n/locales/eu.json b/apps/mobile/src/i18n/locales/eu.json index 74680fad858..0758c0339ed 100644 --- a/apps/mobile/src/i18n/locales/eu.json +++ b/apps/mobile/src/i18n/locales/eu.json @@ -3725,6 +3725,8 @@ "empty": "Kreditu-paketeak ez daude orain erabilgarri.", "noMatchingProducts": "App Store-k ez du bat datorren kreditu-paketerik itzuli.", "noMatchingProductsPlay": "Google Play-k ez du bat datorren kreditu-paketerik itzuli.", + "storeTimedOut": "App Store-k ez du denboran erantzun. Saiatu berriro.", + "storeTimedOutPlay": "Google Play-k ez du denboran erantzun. Saiatu berriro.", "purchaseOwnedByAnotherAccount": "Apple Account honetako kredituak beste Kilo kontu bati dagozkio. Erabiltzeko, hasi saioa Kilo kontu horretan.", "purchaseOwnedByAnotherAccountPlay": "Google Play kontu honetako kredituak beste Kilo kontu bati dagozkio. Erabiltzeko, hasi saioa Kilo kontu horretan." }, diff --git a/apps/mobile/src/i18n/locales/fa.json b/apps/mobile/src/i18n/locales/fa.json index faefe79a64b..b16e20bff5a 100644 --- a/apps/mobile/src/i18n/locales/fa.json +++ b/apps/mobile/src/i18n/locales/fa.json @@ -3725,6 +3725,8 @@ "empty": "بسته‌های اعتبار در حال حاضر در دسترس نیستند.", "noMatchingProducts": "App Store هیچ بسته اعتبار منطبقی برنگرداند.", "noMatchingProductsPlay": "Google Play هیچ بسته اعتبار منطبقی برنگرداند.", + "storeTimedOut": "App Store در زمان مشخص پاسخ نداد. تلاش مجدد", + "storeTimedOutPlay": "Google Play در زمان مشخص پاسخ نداد. تلاش مجدد", "purchaseOwnedByAnotherAccount": "اعتبار این Apple Account متعلق به حساب دیگری در Kilo است. برای استفاده از آن وارد همان حساب Kilo شوید.", "purchaseOwnedByAnotherAccountPlay": "اعتبار این حساب Google Play متعلق به یک حساب Kilo دیگر است. برای استفاده از آن وارد آن حساب Kilo شوید." }, diff --git a/apps/mobile/src/i18n/locales/fi.json b/apps/mobile/src/i18n/locales/fi.json index 829006a3d27..612e18e276e 100644 --- a/apps/mobile/src/i18n/locales/fi.json +++ b/apps/mobile/src/i18n/locales/fi.json @@ -3725,6 +3725,8 @@ "empty": "Krediittipaketit eivät ole juuri nyt saatavilla.", "noMatchingProducts": "App Store ei palauttanut yhtään sopivaa krediittipakettia.", "noMatchingProductsPlay": "Google Play ei palauttanut yhtään sopivaa krediittipakettia.", + "storeTimedOut": "App Store ei vastannut ajoissa. Yritä uudelleen.", + "storeTimedOutPlay": "Google Play ei vastannut ajoissa. Yritä uudelleen.", "purchaseOwnedByAnotherAccount": "Tämän Apple-tilin krediitit kuuluvat toiselle Kilo-tilille. Käytä niitä kirjautumalla kyseiselle Kilo-tilille.", "purchaseOwnedByAnotherAccountPlay": "Tämän Google Play -tilin krediitit kuuluvat eri Kilo-tilille. Käytä niitä kirjautumalla siihen Kilo-tiliin." }, diff --git a/apps/mobile/src/i18n/locales/fil.json b/apps/mobile/src/i18n/locales/fil.json index b063191d993..367befb66c1 100644 --- a/apps/mobile/src/i18n/locales/fil.json +++ b/apps/mobile/src/i18n/locales/fil.json @@ -3725,6 +3725,8 @@ "empty": "Hindi available ang mga credit pack sa ngayon.", "noMatchingProducts": "Walang katugmang credit pack na ibinalik ang App Store.", "noMatchingProductsPlay": "Walang katugmang credit pack na ibinalik ang Google Play.", + "storeTimedOut": "Hindi tumugon sa oras ang App Store. Subukan muli.", + "storeTimedOutPlay": "Hindi tumugon sa oras ang Google Play. Subukan muli.", "purchaseOwnedByAnotherAccount": "Ang kredito sa Apple Account na ito ay kabilang sa ibang Kilo account. Mag-sign in sa Kilo account na iyon para magamit ito.", "purchaseOwnedByAnotherAccountPlay": "Ang kredito sa Google Play account na ito ay kabilang sa ibang Kilo account. Mag-sign in sa Kilo account na iyon para magamit ito." }, diff --git a/apps/mobile/src/i18n/locales/fr.json b/apps/mobile/src/i18n/locales/fr.json index a4d3634edc4..755785a4b00 100644 --- a/apps/mobile/src/i18n/locales/fr.json +++ b/apps/mobile/src/i18n/locales/fr.json @@ -3766,6 +3766,8 @@ "empty": "Les packs de crédits sont indisponibles pour le moment.", "noMatchingProducts": "L'App Store n'a renvoyé aucun pack de crédits correspondant.", "noMatchingProductsPlay": "Google Play n'a renvoyé aucun pack de crédits correspondant.", + "storeTimedOut": "L'App Store n'a pas répondu à temps. Réessayez.", + "storeTimedOutPlay": "Google Play n'a pas répondu à temps. Réessayez.", "purchaseOwnedByAnotherAccount": "Les crédits associés à ce compte Apple Account appartiennent à un autre compte Kilo. Connectez-vous à cet autre compte Kilo pour les utiliser.", "purchaseOwnedByAnotherAccountPlay": "Les crédits sur ce compte Google Play appartiennent à un autre compte Kilo. Connectez-vous à ce compte Kilo pour les utiliser." }, diff --git a/apps/mobile/src/i18n/locales/ga.json b/apps/mobile/src/i18n/locales/ga.json index b0284d042ac..5e8d4fce497 100644 --- a/apps/mobile/src/i18n/locales/ga.json +++ b/apps/mobile/src/i18n/locales/ga.json @@ -3848,6 +3848,8 @@ "empty": "Níl pacáistí creidmheasa ar fáil faoi láthair.", "noMatchingProducts": "Níor thug an App Store aon phacáistí creidmheasa comhoiriúnacha ar ais.", "noMatchingProductsPlay": "Níor thug Google Play aon phacáistí creidmheasa comhoiriúnacha ar ais.", + "storeTimedOut": "Níor fhreagair an App Store in am. Bain triail as arís.", + "storeTimedOutPlay": "Níor fhreagair Google Play in am. Bain triail as arís.", "purchaseOwnedByAnotherAccount": "Baineann na creidmheasanna ar an Apple Account seo le cuntas Kilo eile. Sínigh isteach sa chuntas Kilo sin chun iad a úsáid.", "purchaseOwnedByAnotherAccountPlay": "Baineann na creidmheasanna ar an gcuntas Google Play seo le cuntas Kilo éagsúil. Sínigh isteach sa chuntas Kilo sin chun iad a úsáid." }, diff --git a/apps/mobile/src/i18n/locales/gl.json b/apps/mobile/src/i18n/locales/gl.json index febc9f2eec1..eed3da7f243 100644 --- a/apps/mobile/src/i18n/locales/gl.json +++ b/apps/mobile/src/i18n/locales/gl.json @@ -3725,6 +3725,8 @@ "empty": "Os paquetes de créditos non están dispoñibles agora mesmo.", "noMatchingProducts": "A App Store non devolveu ningún paquete de créditos coincidente.", "noMatchingProductsPlay": "Google Play non devolveu ningún paquete de créditos coincidente.", + "storeTimedOut": "A App Store non respondeu a tempo. Téntao de novo.", + "storeTimedOutPlay": "Google Play non respondeu a tempo. Téntao de novo.", "purchaseOwnedByAnotherAccount": "Os créditos desta Apple Account pertencen a outra conta de Kilo. Inicia sesión nesa conta de Kilo para usalos.", "purchaseOwnedByAnotherAccountPlay": "Os créditos desta conta de Google Play pertencen a outra conta de Kilo. Inicia sesión nesa conta de Kilo para usalos." }, diff --git a/apps/mobile/src/i18n/locales/gu.json b/apps/mobile/src/i18n/locales/gu.json index 511d75fe9a0..5e63b5023a6 100644 --- a/apps/mobile/src/i18n/locales/gu.json +++ b/apps/mobile/src/i18n/locales/gu.json @@ -3725,6 +3725,8 @@ "empty": "ક્રેડિટ પેક અત્યારે ઉપલબ્ધ નથી.", "noMatchingProducts": "App Store એ કોઈ મેળ ખાતું ક્રેડિટ પેક પરત કર્યું નથી.", "noMatchingProductsPlay": "Google Play એ કોઈ મેળ ખાતું ક્રેડિટ પેક પરત કર્યું નથી.", + "storeTimedOut": "App Store એ સમયસર પ્રતિસાદ આપ્યો નથી. ફરી પ્રયત્ન કરો.", + "storeTimedOutPlay": "Google Play એ સમયસર પ્રતિસાદ આપ્યો નથી. ફરી પ્રયત્ન કરો.", "purchaseOwnedByAnotherAccount": "આ Apple Account પરની ક્રેડિટ બીજા Kilo ખાતાની છે. તેનો ઉપયોગ કરવા તે Kilo ખાતામાં સાઇન ઇન કરો.", "purchaseOwnedByAnotherAccountPlay": "આ Google Play ખાતા પરની ક્રેડિટ અલગ Kilo ખાતાની છે. તેનો ઉપયોગ કરવા તે Kilo ખાતામાં સાઇન ઇન કરો." }, diff --git a/apps/mobile/src/i18n/locales/ha.json b/apps/mobile/src/i18n/locales/ha.json index 079a6a2e3a8..bec93c46be8 100644 --- a/apps/mobile/src/i18n/locales/ha.json +++ b/apps/mobile/src/i18n/locales/ha.json @@ -3725,6 +3725,8 @@ "empty": "Fakitin kuɗin amfani ba su nan a yanzu.", "noMatchingProducts": "App Store bai dawo da wani fakitin kuɗin amfani da ya dace ba.", "noMatchingProductsPlay": "Google Play bai dawo da wani fakitin kuɗin amfani da ya dace ba.", + "storeTimedOut": "App Store bai amsa a kan lokaci ba. Sake gwadawa.", + "storeTimedOutPlay": "Google Play bai amsa a kan lokaci ba. Sake gwadawa.", "purchaseOwnedByAnotherAccount": "Kuɗin amfani da ke kan wannan Apple Account na wani asusun Kilo ne daban. Shiga wancan asusun Kilo don amfani da shi.", "purchaseOwnedByAnotherAccountPlay": "Kuɗin amfani da ke kan wannan Google Play account na wani asusun Kilo ne daban. Shiga wannan asusun Kilo don amfani da shi." }, diff --git a/apps/mobile/src/i18n/locales/he.json b/apps/mobile/src/i18n/locales/he.json index 6f0e8bad227..eafd9aa6e41 100644 --- a/apps/mobile/src/i18n/locales/he.json +++ b/apps/mobile/src/i18n/locales/he.json @@ -3766,6 +3766,8 @@ "empty": "חבילות קרדיטים אינן זמינות כעת.", "noMatchingProducts": "App Store לא החזיר חבילות קרדיטים תואמות.", "noMatchingProductsPlay": "Google Play לא החזיר חבילות קרדיטים תואמות.", + "storeTimedOut": "App Store לא הגיב בזמן. ניסיון נוסף.", + "storeTimedOutPlay": "Google Play לא הגיב בזמן. ניסיון נוסף.", "purchaseOwnedByAnotherAccount": "הקרדיטים בחשבון Apple Account הזה שייכים לחשבון Kilo אחר. היכנס לחשבון Kilo הזה כדי להשתמש בהם.", "purchaseOwnedByAnotherAccountPlay": "הקרדיטים בחשבון Google Play הזה שייכים לחשבון Kilo אחר. היכנס לחשבון Kilo הזה כדי להשתמש בהם." }, diff --git a/apps/mobile/src/i18n/locales/hi.json b/apps/mobile/src/i18n/locales/hi.json index 83087a8be0c..ee33540cde9 100644 --- a/apps/mobile/src/i18n/locales/hi.json +++ b/apps/mobile/src/i18n/locales/hi.json @@ -3725,6 +3725,8 @@ "empty": "क्रेडिट पैक अभी उपलब्ध नहीं हैं।", "noMatchingProducts": "App Store ने कोई मेल खाता क्रेडिट पैक नहीं लौटाया।", "noMatchingProductsPlay": "Google Play ने कोई मेल खाता क्रेडिट पैक नहीं लौटाया।", + "storeTimedOut": "App Store ने समय पर जवाब नहीं दिया। फिर से कोशिश करें।", + "storeTimedOutPlay": "Google Play ने समय पर जवाब नहीं दिया। फिर से प्रयास करें।", "purchaseOwnedByAnotherAccount": "इस Apple Account का क्रेडिट किसी दूसरे Kilo खाते से जुड़ा है। इसका उपयोग करने के लिए उस Kilo खाते में साइन इन करें।", "purchaseOwnedByAnotherAccountPlay": "इस Google Play खाते का क्रेडिट किसी दूसरे Kilo खाते से संबंधित है। इसका उपयोग करने के लिए उस Kilo खाते में साइन इन करें।" }, diff --git a/apps/mobile/src/i18n/locales/hr.json b/apps/mobile/src/i18n/locales/hr.json index b5e0672405f..378e1850b99 100644 --- a/apps/mobile/src/i18n/locales/hr.json +++ b/apps/mobile/src/i18n/locales/hr.json @@ -3766,6 +3766,8 @@ "empty": "Paketi kredita trenutačno nisu dostupni.", "noMatchingProducts": "App Store nije vratio odgovarajuće pakete kredita.", "noMatchingProductsPlay": "Google Play nije vratio odgovarajuće pakete kredita.", + "storeTimedOut": "App Store nije odgovorio na vrijeme. Pokušaj ponovno.", + "storeTimedOutPlay": "Google Play nije odgovorio na vrijeme. Pokušaj ponovno.", "purchaseOwnedByAnotherAccount": "Krediti na ovom računu Apple Account pripadaju drugom Kilo računu. Prijavi se na taj Kilo račun da ih koristiš.", "purchaseOwnedByAnotherAccountPlay": "Krediti na ovom Google Play računu pripadaju drugom Kilo računu. Prijavite se na taj Kilo račun da biste ih koristili." }, diff --git a/apps/mobile/src/i18n/locales/ht.json b/apps/mobile/src/i18n/locales/ht.json index f5bfb6b4304..5ae541c7532 100644 --- a/apps/mobile/src/i18n/locales/ht.json +++ b/apps/mobile/src/i18n/locales/ht.json @@ -3725,6 +3725,8 @@ "empty": "Pake kredi yo pa disponib kounye a.", "noMatchingProducts": "App Store pa t retounen okenn pake kredi ki matche.", "noMatchingProductsPlay": "Google Play pa t retounen okenn pake kredi ki matche.", + "storeTimedOut": "App Store pa t reponn a tan. Eseye ankò.", + "storeTimedOutPlay": "Google Play pa t reponn a tan. Eseye ankò.", "purchaseOwnedByAnotherAccount": "Kredi ki sou Apple Account sa a fè pati yon lòt kont Kilo. Konekte nan kont Kilo sa a pou itilize yo.", "purchaseOwnedByAnotherAccountPlay": "Kredi ki sou kont Google Play sa a fè pati yon lòt kont Kilo. Siyen nan kont Kilo sa a pou itilize yo." }, diff --git a/apps/mobile/src/i18n/locales/hu.json b/apps/mobile/src/i18n/locales/hu.json index 9ab5bba6517..a5ed6d3ff66 100644 --- a/apps/mobile/src/i18n/locales/hu.json +++ b/apps/mobile/src/i18n/locales/hu.json @@ -3725,6 +3725,8 @@ "empty": "A kreditcsomagok jelenleg nem érhetők el.", "noMatchingProducts": "Az App Store nem adott vissza megfelelő kreditcsomagot.", "noMatchingProductsPlay": "A Google Play nem adott vissza megfelelő kreditcsomagot.", + "storeTimedOut": "Az App Store nem válaszolt időben. Próbáld újra.", + "storeTimedOutPlay": "A Google Play nem válaszolt időben. Próbáld újra.", "purchaseOwnedByAnotherAccount": "Az ehhez az Apple Account-fiókhoz tartozó kreditek egy másik Kilo-fiókhoz kapcsolódnak. A használatukhoz jelentkezz be abba a Kilo-fiókba.", "purchaseOwnedByAnotherAccountPlay": "Az ezen Google Play-fiókon lévő kreditek egy másik Kilo-fiókhoz tartoznak. A használatukhoz jelentkezz be abba a Kilo-fiókba." }, diff --git a/apps/mobile/src/i18n/locales/hy.json b/apps/mobile/src/i18n/locales/hy.json index da061f4ddcc..2996c246c6c 100644 --- a/apps/mobile/src/i18n/locales/hy.json +++ b/apps/mobile/src/i18n/locales/hy.json @@ -3725,6 +3725,8 @@ "empty": "Կրեդիտային փաթեթներն այժմ հասանելի չեն։", "noMatchingProducts": "App Store-ը համապատասխան կրեդիտային փաթեթներ չվերադարձրեց։", "noMatchingProductsPlay": "Google Play-ը համապատասխան կրեդիտային փաթեթներ չվերադարձրեց։", + "storeTimedOut": "App Store-ը ժամանակին չպատասխանեց։ Կրկին փորձել։", + "storeTimedOutPlay": "Google Play-ը ժամանակին չպատասխանեց։ Կրկին փորձել։", "purchaseOwnedByAnotherAccount": "Այս Apple Account-ի կրեդիտները պատկանում են մեկ այլ Kilo հաշվի։ Դրանք օգտագործելու համար մուտք գործեք այդ Kilo հաշիվ։", "purchaseOwnedByAnotherAccountPlay": "Այս Google Play հաշվի կրեդիտները պատկանում են մեկ այլ Kilo հաշվի։ Դրանք օգտագործելու համար մուտք գործեք այդ Kilo հաշիվ։" }, diff --git a/apps/mobile/src/i18n/locales/id.json b/apps/mobile/src/i18n/locales/id.json index bec8c14145a..1c86b22a715 100644 --- a/apps/mobile/src/i18n/locales/id.json +++ b/apps/mobile/src/i18n/locales/id.json @@ -3725,6 +3725,8 @@ "empty": "Paket kredit tidak tersedia saat ini.", "noMatchingProducts": "App Store tidak mengembalikan paket kredit yang cocok.", "noMatchingProductsPlay": "Google Play tidak mengembalikan paket kredit yang cocok.", + "storeTimedOut": "App Store tidak merespons tepat waktu. Coba lagi.", + "storeTimedOutPlay": "Google Play tidak merespons tepat waktu. Coba lagi.", "purchaseOwnedByAnotherAccount": "Kredit pada Apple Account ini milik akun Kilo yang berbeda. Masuk ke akun Kilo tersebut untuk menggunakannya.", "purchaseOwnedByAnotherAccountPlay": "Kredit di akun Google Play ini milik akun Kilo yang berbeda. Masuk ke akun Kilo tersebut untuk menggunakannya." }, diff --git a/apps/mobile/src/i18n/locales/ig.json b/apps/mobile/src/i18n/locales/ig.json index da4af0e216b..46e91de5959 100644 --- a/apps/mobile/src/i18n/locales/ig.json +++ b/apps/mobile/src/i18n/locales/ig.json @@ -3725,6 +3725,8 @@ "empty": "Ngwugwu ego ojiji adịghị ugbu a.", "noMatchingProducts": "App Store eweghachighị ngwugwu ego ojiji dabara adaba.", "noMatchingProductsPlay": "Google Play eweghachighị ngwugwu ego ojiji dabara adaba.", + "storeTimedOut": "App Store azaghịghị n'oge. Nwaa ọzọ.", + "storeTimedOutPlay": "Google Play azaghịghị n'oge. Nwaa ọzọ.", "purchaseOwnedByAnotherAccount": "Ego ojiji dị na Apple Account a bụ nke akaụntụ Kilo ọzọ. Banye na akaụntụ Kilo ahụ iji jiri ya.", "purchaseOwnedByAnotherAccountPlay": "Ego ojiji dị na akaụntụ Google Play a bụ nke akaụntụ Kilo ọzọ. Banye na akaụntụ Kilo ahụ iji jiri ya." }, diff --git a/apps/mobile/src/i18n/locales/is.json b/apps/mobile/src/i18n/locales/is.json index c987a52e67f..3cb68b0b1b4 100644 --- a/apps/mobile/src/i18n/locales/is.json +++ b/apps/mobile/src/i18n/locales/is.json @@ -3725,6 +3725,8 @@ "empty": "Inneignarpakkar eru ekki tiltækir núna.", "noMatchingProducts": "App Store skilaði engum samsvarandi inneignarpökkum.", "noMatchingProductsPlay": "Google Play skilaði engum samsvarandi inneignarpökkum.", + "storeTimedOut": "App Store svaraði ekki tímanlega. Reyndu aftur.", + "storeTimedOutPlay": "Google Play svaraði ekki tímanlega. Reyndu aftur.", "purchaseOwnedByAnotherAccount": "Inneignin á þessum Apple Account-reikningi tilheyrir öðrum Kilo-reikningi. Skráðu þig inn á þann Kilo-reikning til að nota hana.", "purchaseOwnedByAnotherAccountPlay": "Inneignin á þessum Google Play-reikningi tilheyrir öðrum Kilo-reikningi. Skráðu þig inn á þann Kilo-reikning til að nota hana." }, diff --git a/apps/mobile/src/i18n/locales/it.json b/apps/mobile/src/i18n/locales/it.json index 4cbc18d9ac8..21504730d52 100644 --- a/apps/mobile/src/i18n/locales/it.json +++ b/apps/mobile/src/i18n/locales/it.json @@ -3766,6 +3766,8 @@ "empty": "I pacchetti di crediti non sono disponibili al momento.", "noMatchingProducts": "L'App Store non ha restituito pacchetti di crediti corrispondenti.", "noMatchingProductsPlay": "Google Play non ha restituito pacchetti di crediti corrispondenti.", + "storeTimedOut": "L'App Store non ha risposto in tempo. Riprova.", + "storeTimedOutPlay": "Google Play non ha risposto in tempo. Riprova.", "purchaseOwnedByAnotherAccount": "I crediti associati a questo Apple Account appartengono a un altro account Kilo. Accedi a quell'account Kilo per usarli.", "purchaseOwnedByAnotherAccountPlay": "I crediti su questo account Google Play appartengono a un account Kilo diverso. Accedi a quell'account Kilo per usarli." }, diff --git a/apps/mobile/src/i18n/locales/ja.json b/apps/mobile/src/i18n/locales/ja.json index 8ebfbc66e9f..459e0ab5d86 100644 --- a/apps/mobile/src/i18n/locales/ja.json +++ b/apps/mobile/src/i18n/locales/ja.json @@ -3725,6 +3725,8 @@ "empty": "現在、クレジットパックを利用できません。", "noMatchingProducts": "App Storeから一致するクレジットパックが返されませんでした。", "noMatchingProductsPlay": "Google Playから一致するクレジットパックが返されませんでした。", + "storeTimedOut": "App Storeが時間内に応答しませんでした。再試行", + "storeTimedOutPlay": "Google Playが時間内に応答しませんでした。再試行", "purchaseOwnedByAnotherAccount": "このApple Accountのクレジットは、別のKiloアカウントに紐付いています。使用するには、そのKiloアカウントにサインインしてください。", "purchaseOwnedByAnotherAccountPlay": "このGoogle Playアカウントのクレジットは別のKiloアカウントに属しています。使用するにはそのKiloアカウントにサインインしてください。" }, diff --git a/apps/mobile/src/i18n/locales/ka.json b/apps/mobile/src/i18n/locales/ka.json index 26f62b4dfb0..0b744910e67 100644 --- a/apps/mobile/src/i18n/locales/ka.json +++ b/apps/mobile/src/i18n/locales/ka.json @@ -3725,6 +3725,8 @@ "empty": "კრედიტების პაკეტები ამჟამად მიუწვდომელია.", "noMatchingProducts": "App Store-მა შესაბამისი კრედიტის პაკეტები არ დააბრუნა.", "noMatchingProductsPlay": "Google Play-მა შესაბამისი კრედიტის პაკეტები არ დააბრუნა.", + "storeTimedOut": "App Store-მა დროულად არ უპასუხა. ხელახლა ცდა", + "storeTimedOutPlay": "Google Play-მა დროულად არ უპასუხა. ხელახლა ცდა", "purchaseOwnedByAnotherAccount": "ამ Apple Account-ზე არსებული კრედიტები სხვა Kilo ანგარიშს ეკუთვნის. მათ გამოსაყენებლად შედი იმ Kilo ანგარიშში.", "purchaseOwnedByAnotherAccountPlay": "ამ Google Play ანგარიშზე არსებული კრედიტები სხვა Kilo ანგარიშს ეკუთვნის. მათ გამოსაყენებლად შედით იმ Kilo ანგარიშში." }, diff --git a/apps/mobile/src/i18n/locales/kk.json b/apps/mobile/src/i18n/locales/kk.json index b2bfb86b472..1b74d992549 100644 --- a/apps/mobile/src/i18n/locales/kk.json +++ b/apps/mobile/src/i18n/locales/kk.json @@ -3725,6 +3725,8 @@ "empty": "Кредит пакеттері қазір қолжетімсіз.", "noMatchingProducts": "App Store сәйкес кредит пакеттерін қайтармады.", "noMatchingProductsPlay": "Google Play сәйкес кредит пакеттерін қайтармады.", + "storeTimedOut": "App Store уақытында жауап бермеді. Қайталап көру", + "storeTimedOutPlay": "Google Play уақытында жауап бермеді. Қайталап көру", "purchaseOwnedByAnotherAccount": "Осы Apple Account тіркелгісіндегі кредиттер басқа Kilo тіркелгісіне тиесілі. Оларды пайдалану үшін сол Kilo тіркелгісіне кіріңіз.", "purchaseOwnedByAnotherAccountPlay": "Бұл Google Play аккаунтындағы кредиттер басқа Kilo аккаунтына тиесілі. Оларды пайдалану үшін сол Kilo аккаунтына кіріңіз." }, diff --git a/apps/mobile/src/i18n/locales/km.json b/apps/mobile/src/i18n/locales/km.json index 62523d91b26..2aa287761e7 100644 --- a/apps/mobile/src/i18n/locales/km.json +++ b/apps/mobile/src/i18n/locales/km.json @@ -3725,6 +3725,8 @@ "empty": "កញ្ចប់ឥណទានមិនអាចប្រើបាននៅពេលនេះទេ។", "noMatchingProducts": "App Store មិនបានត្រឡប់កញ្ចប់ឥណទានដែលត្រូវគ្នាទេ។", "noMatchingProductsPlay": "Google Play មិនបានត្រឡប់កញ្ចប់ឥណទានដែលត្រូវគ្នាទេ។", + "storeTimedOut": "App Store មិនបានឆ្លើយតបទាន់ពេលទេ។ ព្យាយាមម្តងទៀត", + "storeTimedOutPlay": "Google Play មិនបានឆ្លើយតបទាន់ពេលទេ។ ព្យាយាមម្តងទៀត", "purchaseOwnedByAnotherAccount": "ឥណទាននៅលើ Apple Account នេះជារបស់គណនី Kilo ផ្សេង។ ចូលគណនី Kilo នោះដើម្បីប្រើវា។", "purchaseOwnedByAnotherAccountPlay": "ឥណទាននៅលើគណនី Google Play នេះជារបស់គណនី Kilo ផ្សេង។ ចូលគណនី Kilo នោះដើម្បីប្រើវា។" }, diff --git a/apps/mobile/src/i18n/locales/kn.json b/apps/mobile/src/i18n/locales/kn.json index 90e6875297b..bbd0fe195ed 100644 --- a/apps/mobile/src/i18n/locales/kn.json +++ b/apps/mobile/src/i18n/locales/kn.json @@ -3725,6 +3725,8 @@ "empty": "ಕ್ರೆಡಿಟ್ ಪ್ಯಾಕ್ಗಳು ಸದ್ಯಕ್ಕೆ ಲಭ್ಯವಿಲ್ಲ.", "noMatchingProducts": "App Store ಯಾವುದೇ ಹೊಂದಿಕೆಯಾಗುವ ಕ್ರೆಡಿಟ್ ಪ್ಯಾಕ್ಗಳನ್ನು ಹಿಂತಿರುಗಿಸಲಿಲ್ಲ.", "noMatchingProductsPlay": "Google Play ಯಾವುದೇ ಹೊಂದಿಕೆಯಾಗುವ ಕ್ರೆಡಿಟ್ ಪ್ಯಾಕ್ಗಳನ್ನು ಹಿಂತಿರುಗಿಸಲಿಲ್ಲ.", + "storeTimedOut": "App Store ಸಮಯಕ್ಕೆ ಸರಿಯಾಗಿ ಪ್ರತಿಕ್ರಿಯಿಸಲಿಲ್ಲ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ", + "storeTimedOutPlay": "Google Play ಸಮಯಕ್ಕೆ ಸರಿಯಾಗಿ ಪ್ರತಿಕ್ರಿಯಿಸಲಿಲ್ಲ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ", "purchaseOwnedByAnotherAccount": "ಈ Apple Account ನಲ್ಲಿನ ಕ್ರೆಡಿಟ್ಗಳು ಬೇರೆ Kilo ಖಾತೆಗೆ ಸೇರಿವೆ. ಅವನ್ನು ಬಳಸಲು ಆ Kilo ಖಾತೆಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ.", "purchaseOwnedByAnotherAccountPlay": "ಈ Google Play ಖಾತೆಯಲ್ಲಿನ ಕ್ರೆಡಿಟ್ಗಳು ಬೇರೆ Kilo ಖಾತೆಗೆ ಸೇರಿವೆ. ಅವನ್ನು ಬಳಸಲು ಆ Kilo ಖಾತೆಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ." }, diff --git a/apps/mobile/src/i18n/locales/ko.json b/apps/mobile/src/i18n/locales/ko.json index 820a806390f..c08d6f3c348 100644 --- a/apps/mobile/src/i18n/locales/ko.json +++ b/apps/mobile/src/i18n/locales/ko.json @@ -3725,6 +3725,8 @@ "empty": "현재 크레딧 팩을 사용할 수 없습니다.", "noMatchingProducts": "App Store에서 일치하는 크레딧 팩을 반환하지 않았습니다.", "noMatchingProductsPlay": "Google Play에서 일치하는 크레딧 팩을 반환하지 않았습니다.", + "storeTimedOut": "App Store에서 제시간에 응답하지 않았습니다. 다시 시도", + "storeTimedOutPlay": "Google Play에서 제시간에 응답하지 않았습니다. 다시 시도", "purchaseOwnedByAnotherAccount": "이 Apple Account의 크레딧은 다른 Kilo 계정에 속해 있습니다. 사용하려면 해당 Kilo 계정에 로그인하세요.", "purchaseOwnedByAnotherAccountPlay": "이 Google Play 계정의 크레딧은 다른 Kilo 계정에 속합니다. 사용하려면 해당 Kilo 계정으로 로그인하세요." }, diff --git a/apps/mobile/src/i18n/locales/lo.json b/apps/mobile/src/i18n/locales/lo.json index fb0c421085e..6fffca3ac26 100644 --- a/apps/mobile/src/i18n/locales/lo.json +++ b/apps/mobile/src/i18n/locales/lo.json @@ -3725,6 +3725,8 @@ "empty": "ແພັກເຄຣດິດບໍ່ສາມາດໃຊ້ໄດ້ໃນຕອນນີ້.", "noMatchingProducts": "App Store ບໍ່ໄດ້ສົ່ງແພັກເຄຣດິດທີ່ກົງກັນຄືນ.", "noMatchingProductsPlay": "Google Play ບໍ່ໄດ້ສົ່ງແພັກເຄຣດິດທີ່ກົງກັນຄືນ.", + "storeTimedOut": "App Store ບໍ່ໄດ້ຕອບສະໜອງທັນເວລາ. ລອງອີກຄັ້ງ.", + "storeTimedOutPlay": "Google Play ບໍ່ໄດ້ຕອບສະໜອງທັນເວລາ. ລອງອີກຄັ້ງ.", "purchaseOwnedByAnotherAccount": "ເຄຣດິດໃນ Apple Account ນີ້ເປັນຂອງບັນຊີ Kilo ອື່ນ. ເຂົ້າສູ່ລະບົບບັນຊີ Kilo ນັ້ນເພື່ອໃຊ້ມັນ.", "purchaseOwnedByAnotherAccountPlay": "ເຄຣດິດໃນບັນຊີ Google Play ນີ້ເປັນຂອງບັນຊີ Kilo ອື່ນ. ເຂົ້າສູ່ລະບົບບັນຊີ Kilo ນັ້ນເພື່ອໃຊ້ມັນ." }, diff --git a/apps/mobile/src/i18n/locales/lt.json b/apps/mobile/src/i18n/locales/lt.json index 6f0cf6c07ae..031df6300b0 100644 --- a/apps/mobile/src/i18n/locales/lt.json +++ b/apps/mobile/src/i18n/locales/lt.json @@ -3807,6 +3807,8 @@ "empty": "Kreditų paketai šiuo metu neprieinami.", "noMatchingProducts": "App Store negrąžino jokių atitinkančių kreditų paketų.", "noMatchingProductsPlay": "Google Play negrąžino jokių atitinkančių kreditų paketų.", + "storeTimedOut": "App Store neatsakė laiku. Bandyti dar kartą.", + "storeTimedOutPlay": "Google Play neatsakė laiku. Bandyti dar kartą.", "purchaseOwnedByAnotherAccount": "Šios Apple Account paskyros kreditai priklauso kitai Kilo paskyrai. Norėdami juos naudoti, prisijunkite prie tos Kilo paskyros.", "purchaseOwnedByAnotherAccountPlay": "Šios Google Play paskyros kreditai priklauso kitai Kilo paskyrai. Norėdami juos naudoti, prisijunkite prie tos Kilo paskyros." }, diff --git a/apps/mobile/src/i18n/locales/lv.json b/apps/mobile/src/i18n/locales/lv.json index 4e499dbb5e0..1598ec4d8d6 100644 --- a/apps/mobile/src/i18n/locales/lv.json +++ b/apps/mobile/src/i18n/locales/lv.json @@ -3766,6 +3766,8 @@ "empty": "Kredītu paketes šobrīd nav pieejamas.", "noMatchingProducts": "App Store neatgrieza nevienu atbilstošu kredītu paketi.", "noMatchingProductsPlay": "Google Play neatgrieza nevienu atbilstošu kredītu paketi.", + "storeTimedOut": "App Store neatbildēja laicīgi. Mēģināt vēlreiz.", + "storeTimedOutPlay": "Google Play neatbildēja laicīgi. Mēģināt vēlreiz.", "purchaseOwnedByAnotherAccount": "Kredīti šajā Apple Account kontā pieder citam Kilo kontam. Lai tos izmantotu, pieraksties attiecīgajā Kilo kontā.", "purchaseOwnedByAnotherAccountPlay": "Kredīti šajā Google Play kontā pieder citam Kilo kontam. Lai tos izmantotu, piesakieties tajā Kilo kontā." }, diff --git a/apps/mobile/src/i18n/locales/mg.json b/apps/mobile/src/i18n/locales/mg.json index 35b27b33f87..4115877b6bc 100644 --- a/apps/mobile/src/i18n/locales/mg.json +++ b/apps/mobile/src/i18n/locales/mg.json @@ -3725,6 +3725,8 @@ "empty": "Tsy misy ny fonosana kireditra amin'izao fotoana izao.", "noMatchingProducts": "Tsy nisy fonosana kireditra mifanaraka naverin'ny App Store.", "noMatchingProductsPlay": "Tsy nisy fonosana kireditra mifanaraka naverin'ny Google Play.", + "storeTimedOut": "Tsy namaly tamin'ny fotoana ilay App Store. Andramo indray.", + "storeTimedOutPlay": "Tsy namaly tamin'ny fotoana ilay Google Play. Andramo indray.", "purchaseOwnedByAnotherAccount": "Ny kireditra amin'ity Apple Account ity dia an'ny kaonty Kilo hafa. Midira amin'izany kaonty Kilo izany hampiasana azy.", "purchaseOwnedByAnotherAccountPlay": "Ny kireditra amin'ity kaonty Google Play ity dia an'ny kaonty Kilo hafa. Midira amin'izany kaonty Kilo izany hampiasana azy." }, diff --git a/apps/mobile/src/i18n/locales/mi.json b/apps/mobile/src/i18n/locales/mi.json index 767f728f431..e49316d98bb 100644 --- a/apps/mobile/src/i18n/locales/mi.json +++ b/apps/mobile/src/i18n/locales/mi.json @@ -3725,6 +3725,8 @@ "empty": "Kāore ngā pākete whiwhinga e wātea ana i tēnei wā.", "noMatchingProducts": "Kāore te App Store i whakahoki i ētahi pākete whiwhinga ōrite.", "noMatchingProductsPlay": "Kāore Google Play i whakahoki i ētahi pākete whiwhinga ōrite.", + "storeTimedOut": "Kāore te App Store i whakautu i te wā. Whakamātau anō.", + "storeTimedOutPlay": "Kāore a Google Play i whakautu i te wā. Whakamātau anō.", "purchaseOwnedByAnotherAccount": "Nō tētahi atu pūkete Kilo ngā whiwhinga o tēnei Apple Account. Whakauru ki taua pūkete Kilo hei whakamahi.", "purchaseOwnedByAnotherAccountPlay": "Nō tētahi atu pūkete Kilo ngā whiwhinga o tēnei pūkete Google Play. Whakauru ki taua pūkete Kilo hei whakamahi." }, diff --git a/apps/mobile/src/i18n/locales/mk.json b/apps/mobile/src/i18n/locales/mk.json index c28305687b3..0a7018d60d5 100644 --- a/apps/mobile/src/i18n/locales/mk.json +++ b/apps/mobile/src/i18n/locales/mk.json @@ -3725,6 +3725,8 @@ "empty": "Пакетите со кредити во моментов не се достапни.", "noMatchingProducts": "App Store не врати соодветни пакети со кредити.", "noMatchingProductsPlay": "Google Play не врати соодветни пакети со кредити.", + "storeTimedOut": "App Store не одговори на време. Обиди се повторно.", + "storeTimedOutPlay": "Google Play не одговори на време. Обиди се повторно.", "purchaseOwnedByAnotherAccount": "Кредитите на оваа Apple Account припаѓаат на друга сметка на Kilo. Најави се на таа сметка на Kilo за да ги користиш.", "purchaseOwnedByAnotherAccountPlay": "Кредитите на оваа Google Play сметка припаѓаат на друга Kilo сметка. Најавете се на таа Kilo сметка за да ги користите." }, diff --git a/apps/mobile/src/i18n/locales/ml.json b/apps/mobile/src/i18n/locales/ml.json index e5050d2b69d..2a4ce59e9a3 100644 --- a/apps/mobile/src/i18n/locales/ml.json +++ b/apps/mobile/src/i18n/locales/ml.json @@ -3725,6 +3725,8 @@ "empty": "ക്രെഡിറ്റ് പാക്കുകൾ ഇപ്പോൾ ലഭ്യമല്ല.", "noMatchingProducts": "App Store പൊരുത്തപ്പെടുന്ന ക്രെഡിറ്റ് പാക്കുകൾ തിരികെ നൽകിയില്ല.", "noMatchingProductsPlay": "Google Play പൊരുത്തപ്പെടുന്ന ക്രെഡിറ്റ് പാക്കുകൾ തിരികെ നൽകിയില്ല.", + "storeTimedOut": "App Store സമയത്തിനുള്ളിൽ പ്രതികരിച്ചില്ല. വീണ്ടും ശ്രമിക്കുക.", + "storeTimedOutPlay": "Google Play സമയത്തിനുള്ളിൽ പ്രതികരിച്ചില്ല. വീണ്ടും ശ്രമിക്കുക.", "purchaseOwnedByAnotherAccount": "ഈ Apple Account-ലെ ക്രെഡിറ്റുകൾ മറ്റൊരു Kilo അക്കൗണ്ടിന്റേതാണ്. അവ ഉപയോഗിക്കാൻ ആ Kilo അക്കൗണ്ടിൽ സൈൻ ഇൻ ചെയ്യുക.", "purchaseOwnedByAnotherAccountPlay": "ഈ Google Play അക്കൗണ്ടിലെ ക്രെഡിറ്റുകൾ മറ്റൊരു Kilo അക്കൗണ്ടിന്റേതാണ്. അവ ഉപയോഗിക്കാൻ ആ Kilo അക്കൗണ്ടിൽ സൈൻ ഇൻ ചെയ്യുക." }, diff --git a/apps/mobile/src/i18n/locales/mn.json b/apps/mobile/src/i18n/locales/mn.json index adef823ca9d..ea021a05b33 100644 --- a/apps/mobile/src/i18n/locales/mn.json +++ b/apps/mobile/src/i18n/locales/mn.json @@ -3725,6 +3725,8 @@ "empty": "Кредит багцууд одоогоор боломжгүй байна.", "noMatchingProducts": "App Store тохирох кредит багц буцаагаагүй.", "noMatchingProductsPlay": "Google Play тохирох кредит багц буцаагаагүй.", + "storeTimedOut": "App Store хугацаандаа хариу өгөөгүй. Дахин оролдох", + "storeTimedOutPlay": "Google Play хугацаандаа хариу өгөөгүй. Дахин оролдох", "purchaseOwnedByAnotherAccount": "Энэ Apple Account дээрх кредит нь өөр Kilo бүртгэлд харьяалагдана. Ашиглахын тулд тухайн Kilo бүртгэлдээ нэвтэрнэ үү.", "purchaseOwnedByAnotherAccountPlay": "Энэ Google Play бүртгэл дээрх кредит нь өөр Kilo бүртгэлд харьяалагдана. Ашиглахын тулд тухайн Kilo бүртгэлдээ нэвтэрнэ үү." }, diff --git a/apps/mobile/src/i18n/locales/mr.json b/apps/mobile/src/i18n/locales/mr.json index ef88f86a01a..6f0f38974c3 100644 --- a/apps/mobile/src/i18n/locales/mr.json +++ b/apps/mobile/src/i18n/locales/mr.json @@ -3725,6 +3725,8 @@ "empty": "क्रेडिट्स पॅक सध्या उपलब्ध नाहीत.", "noMatchingProducts": "App Store ने जुळणारे क्रेडिट्स पॅक परत केले नाहीत.", "noMatchingProductsPlay": "Google Play ने जुळणारे क्रेडिट्स पॅक परत केले नाहीत.", + "storeTimedOut": "App Store ने वेळेत प्रतिसाद दिला नाही. पुन्हा प्रयत्न करा.", + "storeTimedOutPlay": "Google Play ने वेळेत प्रतिसाद दिला नाही. पुन्हा प्रयत्न करा.", "purchaseOwnedByAnotherAccount": "या Apple Account वरील क्रेडिट्स दुसऱ्या Kilo खात्याशी जोडलेली आहेत. ती वापरण्यासाठी त्या Kilo खात्यात साइन इन करा.", "purchaseOwnedByAnotherAccountPlay": "या Google Play खात्यावरील क्रेडिट्स वेगळ्या Kilo खात्याची आहेत. ती वापरण्यासाठी त्या Kilo खात्यावर साइन इन करा." }, diff --git a/apps/mobile/src/i18n/locales/ms.json b/apps/mobile/src/i18n/locales/ms.json index feff4007c30..2b6ba32b3f9 100644 --- a/apps/mobile/src/i18n/locales/ms.json +++ b/apps/mobile/src/i18n/locales/ms.json @@ -3725,6 +3725,8 @@ "empty": "Pek kredit tidak tersedia buat masa ini.", "noMatchingProducts": "App Store tidak memulangkan pek kredit yang sepadan.", "noMatchingProductsPlay": "Google Play tidak memulangkan pek kredit yang sepadan.", + "storeTimedOut": "App Store tidak membalas dalam masa yang ditetapkan. Cuba lagi.", + "storeTimedOutPlay": "Google Play tidak membalas dalam masa yang ditetapkan. Cuba lagi.", "purchaseOwnedByAnotherAccount": "Kredit dalam Apple Account ini milik akaun Kilo yang lain. Log masuk ke akaun Kilo itu untuk menggunakannya.", "purchaseOwnedByAnotherAccountPlay": "Kredit pada Akaun Google Play ini kepunyaan akaun Kilo yang berbeza. Log masuk ke akaun Kilo itu untuk menggunakannya." }, diff --git a/apps/mobile/src/i18n/locales/mt.json b/apps/mobile/src/i18n/locales/mt.json index 4a98d40dbc7..9f8486093c1 100644 --- a/apps/mobile/src/i18n/locales/mt.json +++ b/apps/mobile/src/i18n/locales/mt.json @@ -3848,6 +3848,8 @@ "empty": "Il-pakketti tal-krediti mhumiex disponibbli bħalissa.", "noMatchingProducts": "L-App Store ma rritornax pakketti tal-krediti li jaqblu.", "noMatchingProductsPlay": "Google Play ma rritornax pakketti tal-krediti li jaqblu.", + "storeTimedOut": "L-App Store ma wieġebx f'ħinha. Erġa' pprova.", + "storeTimedOutPlay": "Google Play ma wieġebx f'ħinha. Erġa' pprova.", "purchaseOwnedByAnotherAccount": "Il-krediti fuq dan l-Apple Account jappartjenu għal kont ieħor ta' Kilo. Idħol f'dak il-kont ta' Kilo biex tużahom.", "purchaseOwnedByAnotherAccountPlay": "Il-krediti fuq dan il-kont ta' Google Play jappartjenu għal kont ieħor ta' Kilo. Idħol f'dak il-kont ta' Kilo biex tużahom." }, diff --git a/apps/mobile/src/i18n/locales/my.json b/apps/mobile/src/i18n/locales/my.json index d401132738d..115f8bd79cb 100644 --- a/apps/mobile/src/i18n/locales/my.json +++ b/apps/mobile/src/i18n/locales/my.json @@ -3725,6 +3725,8 @@ "empty": "ခရက်ဒစ် ပက်ခ်များ ယခု မရနိုင်ပါ။", "noMatchingProducts": "App Store မှ ကိုက်ညီသော ခရက်ဒစ် ပက်ခ်များ ပြန်မပေးပါ။", "noMatchingProductsPlay": "Google Play မှ ကိုက်ညီသော ခရက်ဒစ် ပက်ခ်များ ပြန်မပေးပါ။", + "storeTimedOut": "App Store မှ အချိန်အတွင်း တုံ့ပြန်မှု မရှိပါ။ ထပ်စမ်းကြည့်ပါ။", + "storeTimedOutPlay": "Google Play မှ အချိန်အတွင်း တုံ့ပြန်မှု မရှိပါ။ ထပ်စမ်းကြည့်ပါ။", "purchaseOwnedByAnotherAccount": "ဤ Apple Account ရှိ ခရက်ဒစ်များသည် အခြား Kilo အကောင့်တစ်ခုနှင့် သက်ဆိုင်သည်။ အသုံးပြုရန် ထို Kilo အကောင့်ဖြင့် ဝင်ပါ။", "purchaseOwnedByAnotherAccountPlay": "ဤ Google Play အကောင့်ရှိ ခရက်ဒစ်များသည် အခြား Kilo အကောင့်တစ်ခုနှင့် သက်ဆိုင်သည်။ အသုံးပြုရန် ထို Kilo အကောင့်ဖြင့် ဝင်ပါ။" }, diff --git a/apps/mobile/src/i18n/locales/nb.json b/apps/mobile/src/i18n/locales/nb.json index aa9241d8b50..aa10ca6466e 100644 --- a/apps/mobile/src/i18n/locales/nb.json +++ b/apps/mobile/src/i18n/locales/nb.json @@ -3725,6 +3725,8 @@ "empty": "Kredittpakker er ikke tilgjengelige akkurat nå.", "noMatchingProducts": "App Store returnerte ingen samsvarende kredittpakker.", "noMatchingProductsPlay": "Google Play returnerte ingen samsvarende kredittpakker.", + "storeTimedOut": "App Store svarte ikke i tide. Prøv igjen.", + "storeTimedOutPlay": "Google Play svarte ikke i tide. Prøv igjen.", "purchaseOwnedByAnotherAccount": "Kredittene på denne Apple-kontoen tilhører en annen Kilo-konto. Logg inn på den Kilo-kontoen for å bruke dem.", "purchaseOwnedByAnotherAccountPlay": "Kredittene på denne Google Play-kontoen tilhører en annen Kilo-konto. Logg inn på den Kilo-kontoen for å bruke dem." }, diff --git a/apps/mobile/src/i18n/locales/ne.json b/apps/mobile/src/i18n/locales/ne.json index e13166f95cb..27cc9f7c6f0 100644 --- a/apps/mobile/src/i18n/locales/ne.json +++ b/apps/mobile/src/i18n/locales/ne.json @@ -3725,6 +3725,8 @@ "empty": "क्रेडिट प्याकहरू अहिले उपलब्ध छैनन्।", "noMatchingProducts": "App Store ले कुनै मिल्दो क्रेडिट प्याक फर्काएन।", "noMatchingProductsPlay": "Google Play ले कुनै मिल्दो क्रेडिट प्याक फर्काएन।", + "storeTimedOut": "App Store ले समयमै जवाफ दिएन। फेरि प्रयास गर्नुहोस्।", + "storeTimedOutPlay": "Google Play ले समयमै जवाफ दिएन। फेरि प्रयास गर्नुहोस्।", "purchaseOwnedByAnotherAccount": "यो Apple Account मा रहेको क्रेडिट अर्कै Kilo खाताको हो। प्रयोग गर्न त्यही Kilo खातामा साइन इन गर्नुहोस्।", "purchaseOwnedByAnotherAccountPlay": "यो Google Play खातामा रहेको क्रेडिट अर्को Kilo खातासँग सम्बन्धित छ। प्रयोग गर्न त्यो Kilo खातामा साइन इन गर्नुहोस्।" }, diff --git a/apps/mobile/src/i18n/locales/nl.json b/apps/mobile/src/i18n/locales/nl.json index fcd8c74e093..fd22971462a 100644 --- a/apps/mobile/src/i18n/locales/nl.json +++ b/apps/mobile/src/i18n/locales/nl.json @@ -3725,6 +3725,8 @@ "empty": "Creditpakketten zijn momenteel niet beschikbaar.", "noMatchingProducts": "De App Store heeft geen overeenkomende creditpakketten geretourneerd.", "noMatchingProductsPlay": "Google Play heeft geen overeenkomende creditpakketten geretourneerd.", + "storeTimedOut": "De App Store reageerde niet op tijd. Opnieuw proberen.", + "storeTimedOutPlay": "Google Play reageerde niet op tijd. Opnieuw proberen.", "purchaseOwnedByAnotherAccount": "De credits op deze Apple Account horen bij een ander Kilo-account. Meld je aan bij dat Kilo-account om ze te gebruiken.", "purchaseOwnedByAnotherAccountPlay": "De credits op dit Google Play-account horen bij een ander Kilo-account. Meld je aan bij dat Kilo-account om ze te gebruiken." }, diff --git a/apps/mobile/src/i18n/locales/om.json b/apps/mobile/src/i18n/locales/om.json index 42ff37cd6df..ca3d9c4431f 100644 --- a/apps/mobile/src/i18n/locales/om.json +++ b/apps/mobile/src/i18n/locales/om.json @@ -3725,6 +3725,8 @@ "empty": "Paakeejii kireeditii yeroo ammaa hin argamu.", "noMatchingProducts": "App Store paakeejii kireeditii walsimu hin deebisne.", "noMatchingProductsPlay": "Google Play paakeejii kireeditii walsimu hin deebisne.", + "storeTimedOut": "App Store yeroo kessatti hin deebine. Irra deebi'ii yaali.", + "storeTimedOutPlay": "Google Play yeroo kessatti hin deebine. Irra deebi'ii yaali.", "purchaseOwnedByAnotherAccount": "Kireeditiin Apple Account kana irratti jiru kan herrega Kilo biraati. Fayyadamuuf herrega Kilo sanatti seeni.", "purchaseOwnedByAnotherAccountPlay": "Kireeditiin akaawuntii Google Play kana irratti jiru akaawuntii Kilo adda tokko kan ta'e dha. Fayyadamuuf akaawuntii Kilo sana seeni." }, diff --git a/apps/mobile/src/i18n/locales/or.json b/apps/mobile/src/i18n/locales/or.json index b52991f63e1..3f68f69820e 100644 --- a/apps/mobile/src/i18n/locales/or.json +++ b/apps/mobile/src/i18n/locales/or.json @@ -3725,6 +3725,8 @@ "empty": "କ୍ରେଡିଟ୍ ପ୍ୟାକ୍ ବର୍ତ୍ତମାନ ଉପଲବ୍ଧ ନାହିଁ।", "noMatchingProducts": "App Store କୌଣସି ମେଳ ଖାଉଥିବା କ୍ରେଡିଟ୍ ପ୍ୟାକ୍ ଫେରାଇ ନାହିଁ।", "noMatchingProductsPlay": "Google Play କୌଣସି ମେଳ ଖାଉଥିବା କ୍ରେଡିଟ୍ ପ୍ୟାକ୍ ଫେରାଇ ନାହିଁ।", + "storeTimedOut": "App Store ସମୟରେ ଉତ୍ତର ଦେଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।", + "storeTimedOutPlay": "Google Play ସମୟରେ ଉତ୍ତର ଦେଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।", "purchaseOwnedByAnotherAccount": "ଏହି Apple Account ରେ ଥିବା କ୍ରେଡିଟ୍ ଅନ୍ୟ ଏକ Kilo ଆକାଉଣ୍ଟର। ଏହାକୁ ବ୍ୟବହାର କରିବାକୁ ସେହି Kilo ଆକାଉଣ୍ଟରେ ସାଇନ୍ ଇନ୍ କରନ୍ତୁ।", "purchaseOwnedByAnotherAccountPlay": "ଏହି Google Play ଆକାଉଣ୍ଟରେ ଥିବା କ୍ରେଡିଟ୍ ଅନ୍ୟ ଏକ Kilo ଆକାଉଣ୍ଟର ଅଟେ। ଏହାକୁ ବ୍ୟବହାର କରିବାକୁ ସେହି Kilo ଆକାଉଣ୍ଟରେ ସାଇନ୍ ଇନ୍ କରନ୍ତୁ।" }, diff --git a/apps/mobile/src/i18n/locales/pa.json b/apps/mobile/src/i18n/locales/pa.json index c76a1aa4322..4d33e8c6114 100644 --- a/apps/mobile/src/i18n/locales/pa.json +++ b/apps/mobile/src/i18n/locales/pa.json @@ -3725,6 +3725,8 @@ "empty": "ਕ੍ਰੈਡਿਟ ਪੈਕ ਇਸ ਸਮੇਂ ਉਪਲਬਧ ਨਹੀਂ ਹਨ।", "noMatchingProducts": "App Store ਨੇ ਕੋਈ ਮੇਲ ਖਾਂਦਾ ਕ੍ਰੈਡਿਟ ਪੈਕ ਵਾਪਸ ਨਹੀਂ ਕੀਤਾ।", "noMatchingProductsPlay": "Google Play ਨੇ ਕੋਈ ਮੇਲ ਖਾਂਦਾ ਕ੍ਰੈਡਿਟ ਪੈਕ ਵਾਪਸ ਨਹੀਂ ਕੀਤਾ।", + "storeTimedOut": "App Store ਨੇ ਸਮੇਂ ਸਿਰ ਜਵਾਬ ਨਹੀਂ ਦਿੱਤਾ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।", + "storeTimedOutPlay": "Google Play ਨੇ ਸਮੇਂ ਸਿਰ ਜਵਾਬ ਨਹੀਂ ਦਿੱਤਾ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।", "purchaseOwnedByAnotherAccount": "ਇਸ Apple Account ਵਾਲੇ ਕ੍ਰੈਡਿਟ ਕਿਸੇ ਹੋਰ Kilo ਖਾਤੇ ਨਾਲ ਸਬੰਧਤ ਹਨ। ਇਹਨਾਂ ਨੂੰ ਵਰਤਣ ਲਈ ਉਸ Kilo ਖਾਤੇ ਵਿੱਚ ਸਾਈਨ ਇਨ ਕਰੋ।", "purchaseOwnedByAnotherAccountPlay": "ਇਸ Google Play ਖਾਤੇ 'ਤੇ ਕ੍ਰੈਡਿਟ ਇੱਕ ਵੱਖਰੇ Kilo ਖਾਤੇ ਨਾਲ ਸਬੰਧਤ ਹਨ। ਇਹਨਾਂ ਨੂੰ ਵਰਤਣ ਲਈ ਉਸ Kilo ਖਾਤੇ ਵਿੱਚ ਸਾਈਨ ਇਨ ਕਰੋ।" }, diff --git a/apps/mobile/src/i18n/locales/pl.json b/apps/mobile/src/i18n/locales/pl.json index 4befd12ba40..bdb56ce6351 100644 --- a/apps/mobile/src/i18n/locales/pl.json +++ b/apps/mobile/src/i18n/locales/pl.json @@ -3807,6 +3807,8 @@ "empty": "Pakiety kredytów są obecnie niedostępne.", "noMatchingProducts": "App Store nie zwrócił pasujących pakietów kredytów.", "noMatchingProductsPlay": "Google Play nie zwrócił pasujących pakietów kredytów.", + "storeTimedOut": "App Store nie odpowiedział na czas. Spróbuj ponownie.", + "storeTimedOutPlay": "Google Play nie odpowiedział na czas. Spróbuj ponownie.", "purchaseOwnedByAnotherAccount": "Kredyty na tym koncie Apple należą do innego konta Kilo. Zaloguj się na to konto Kilo, aby z nich korzystać.", "purchaseOwnedByAnotherAccountPlay": "Kredyty na tym koncie Google Play należą do innego konta Kilo. Zaloguj się na to konto Kilo, aby z nich korzystać." }, diff --git a/apps/mobile/src/i18n/locales/ps.json b/apps/mobile/src/i18n/locales/ps.json index d8d3984187c..a4eef60ec25 100644 --- a/apps/mobile/src/i18n/locales/ps.json +++ b/apps/mobile/src/i18n/locales/ps.json @@ -3725,6 +3725,8 @@ "empty": "د کریډیټ بنډلونه اوس شتون نلري.", "noMatchingProducts": "App Store د سمون خور کریډیټ بنډلونه بیرته را نه کړل.", "noMatchingProductsPlay": "Google Play د سمون خور کریډیټ بنډلونه بیرته را نه کړل.", + "storeTimedOut": "App Store په وخت کې ځواب ورنه کړ. بیا هڅه وکړئ.", + "storeTimedOutPlay": "Google Play په وخت کې ځواب ورنه کړ. بیا هڅه وکړئ.", "purchaseOwnedByAnotherAccount": "په دې Apple Account کې کریډیټونه د Kilo په بل حساب پورې اړه لري. د کارولو لپاره یې د Kilo هماغه حساب ته ننوځئ.", "purchaseOwnedByAnotherAccountPlay": "دا Google Play حساب باندې کریډیټونه د بل Kilo حساب پورې اړه لري. د کارولو لپاره هغه Kilo حساب ته ننوځئ." }, diff --git a/apps/mobile/src/i18n/locales/pt-BR.json b/apps/mobile/src/i18n/locales/pt-BR.json index 73009391cc6..66cfd10a98f 100644 --- a/apps/mobile/src/i18n/locales/pt-BR.json +++ b/apps/mobile/src/i18n/locales/pt-BR.json @@ -3766,6 +3766,8 @@ "empty": "Os pacotes de créditos estão indisponíveis no momento.", "noMatchingProducts": "A App Store não retornou nenhum pacote de créditos correspondente.", "noMatchingProductsPlay": "O Google Play não retornou nenhum pacote de créditos correspondente.", + "storeTimedOut": "A App Store não respondeu a tempo. Tente novamente.", + "storeTimedOutPlay": "O Google Play não respondeu a tempo. Tente novamente.", "purchaseOwnedByAnotherAccount": "Os créditos desta Conta Apple pertencem a uma conta Kilo diferente. Entre nessa conta Kilo para usá-los.", "purchaseOwnedByAnotherAccountPlay": "Os créditos nesta conta do Google Play pertencem a uma conta Kilo diferente. Entre nessa conta Kilo para usá-los." }, diff --git a/apps/mobile/src/i18n/locales/pt.json b/apps/mobile/src/i18n/locales/pt.json index aec5714c8f6..369b516abf4 100644 --- a/apps/mobile/src/i18n/locales/pt.json +++ b/apps/mobile/src/i18n/locales/pt.json @@ -3766,6 +3766,8 @@ "empty": "Os pacotes de créditos estão indisponíveis de momento.", "noMatchingProducts": "A App Store não devolveu nenhum pacote de créditos correspondente.", "noMatchingProductsPlay": "O Google Play não devolveu nenhum pacote de créditos correspondente.", + "storeTimedOut": "A App Store não respondeu a tempo. Tenta novamente.", + "storeTimedOutPlay": "O Google Play não respondeu a tempo. Tenta novamente.", "purchaseOwnedByAnotherAccount": "Os créditos desta Apple Account pertencem a outra conta Kilo. Inicia sessão nessa conta Kilo para os usares.", "purchaseOwnedByAnotherAccountPlay": "Os créditos desta conta do Google Play pertencem a uma conta Kilo diferente. Inicie sessão nessa conta Kilo para os usar." }, diff --git a/apps/mobile/src/i18n/locales/ro.json b/apps/mobile/src/i18n/locales/ro.json index f38a5c4f302..03ee8e6f1f4 100644 --- a/apps/mobile/src/i18n/locales/ro.json +++ b/apps/mobile/src/i18n/locales/ro.json @@ -3766,6 +3766,8 @@ "empty": "Pachetele de credite nu sunt disponibile momentan.", "noMatchingProducts": "App Store nu a returnat pachete de credite corespunzătoare.", "noMatchingProductsPlay": "Google Play nu a returnat pachete de credite corespunzătoare.", + "storeTimedOut": "App Store nu a răspuns la timp. Încearcă din nou.", + "storeTimedOutPlay": "Google Play nu a răspuns la timp. Încearcă din nou.", "purchaseOwnedByAnotherAccount": "Creditele asociate acestui Apple Account aparțin unui alt cont Kilo. Autentifică-te în acel cont Kilo pentru a le folosi.", "purchaseOwnedByAnotherAccountPlay": "Creditele de pe acest cont Google Play aparțin unui alt cont Kilo. Autentifică-te în acel cont Kilo pentru a le folosi." }, diff --git a/apps/mobile/src/i18n/locales/ru.json b/apps/mobile/src/i18n/locales/ru.json index 7dcd532c19d..1d103fd3350 100644 --- a/apps/mobile/src/i18n/locales/ru.json +++ b/apps/mobile/src/i18n/locales/ru.json @@ -3807,6 +3807,8 @@ "empty": "Пакеты кредитов сейчас недоступны.", "noMatchingProducts": "App Store не вернул подходящие пакеты кредитов.", "noMatchingProductsPlay": "Google Play не вернул подходящие пакеты кредитов.", + "storeTimedOut": "App Store не ответил вовремя. Попробовать снова.", + "storeTimedOutPlay": "Google Play не ответил вовремя. Попробовать снова.", "purchaseOwnedByAnotherAccount": "Кредиты в этом Apple Account связаны с другим аккаунтом Kilo. Войдите в тот аккаунт Kilo, чтобы их использовать.", "purchaseOwnedByAnotherAccountPlay": "Кредиты на этом Google Play аккаунте принадлежат другому аккаунту Kilo. Войдите в тот аккаунт Kilo, чтобы их использовать." }, diff --git a/apps/mobile/src/i18n/locales/si.json b/apps/mobile/src/i18n/locales/si.json index 6c4d7dad5ac..c562a72e270 100644 --- a/apps/mobile/src/i18n/locales/si.json +++ b/apps/mobile/src/i18n/locales/si.json @@ -3725,6 +3725,8 @@ "empty": "ක්‍රෙඩිට් පැකේජ දැනට නොමැත.", "noMatchingProducts": "App Store ගැළපෙන ක්‍රෙඩිට් පැකේජ ආපසු ලබා දුන්නේ නැත.", "noMatchingProductsPlay": "Google Play ගැළපෙන ක්‍රෙඩිට් පැකේජ ආපසු ලබා දුන්නේ නැත.", + "storeTimedOut": "App Store නියමිත වේලාව තුළ ප්‍රතිචාර නොදැක්වීය. නැවත උත්සාහ කරන්න.", + "storeTimedOutPlay": "Google Play නියමිත වේලාව තුළ ප්‍රතිචාර නොදැක්වීය. නැවත උත්සාහ කරන්න.", "purchaseOwnedByAnotherAccount": "මෙම Apple Account හි ක්‍රෙඩිට් වෙනත් Kilo ගිණුමකට අයත් වේ. ඒවා භාවිත කිරීමට එම Kilo ගිණුමට පිවිසෙන්න.", "purchaseOwnedByAnotherAccountPlay": "මෙම Google Play ගිණුමේ ක්‍රෙඩිට් වෙනත් Kilo ගිණුමකට අයත් වේ. ඒවා භාවිත කිරීමට එම Kilo ගිණුමට පුරනය වන්න." }, diff --git a/apps/mobile/src/i18n/locales/sk.json b/apps/mobile/src/i18n/locales/sk.json index 458ec2ed1b2..c6da291aa50 100644 --- a/apps/mobile/src/i18n/locales/sk.json +++ b/apps/mobile/src/i18n/locales/sk.json @@ -3807,6 +3807,8 @@ "empty": "Balíky kreditov teraz nie sú k dispozícii.", "noMatchingProducts": "App Store nevrátil žiadne zodpovedajúce balíky kreditov.", "noMatchingProductsPlay": "Google Play nevrátil žiadne zodpovedajúce balíky kreditov.", + "storeTimedOut": "App Store nereagoval včas. Skúste to znova.", + "storeTimedOutPlay": "Google Play nereagoval včas. Skúste to znova.", "purchaseOwnedByAnotherAccount": "Kredity na tomto účte Apple Account patria inému účtu Kilo. Ak ich chcete použiť, prihláste sa do príslušného účtu Kilo.", "purchaseOwnedByAnotherAccountPlay": "Kredity na tomto účte Google Play patria inému účtu Kilo. Prihláste sa do tohto účtu Kilo, aby ste ich použili." }, diff --git a/apps/mobile/src/i18n/locales/sl.json b/apps/mobile/src/i18n/locales/sl.json index 7d7872b6ccc..7f2149763d3 100644 --- a/apps/mobile/src/i18n/locales/sl.json +++ b/apps/mobile/src/i18n/locales/sl.json @@ -3807,6 +3807,8 @@ "empty": "Paketi kreditov trenutno niso na voljo.", "noMatchingProducts": "App Store ni vrnil ustreznih paketov kreditov.", "noMatchingProductsPlay": "Google Play ni vrnil ustreznih paketov kreditov.", + "storeTimedOut": "App Store ni pravočasno odgovoril. Poskusi znova.", + "storeTimedOutPlay": "Google Play ni pravočasno odgovoril. Poskusi znova.", "purchaseOwnedByAnotherAccount": "Krediti v tem računu Apple Account pripadajo drugemu računu Kilo. Za uporabo se prijavi v ta račun Kilo.", "purchaseOwnedByAnotherAccountPlay": "Krediti na tem Google Play računu pripadajo drugemu Kilo računu. Za uporabo se prijavite v ta Kilo račun." }, diff --git a/apps/mobile/src/i18n/locales/so.json b/apps/mobile/src/i18n/locales/so.json index 6afc54d62f0..6445cfac9ec 100644 --- a/apps/mobile/src/i18n/locales/so.json +++ b/apps/mobile/src/i18n/locales/so.json @@ -3725,6 +3725,8 @@ "empty": "Xirmooyinka lacagta adeeg hadda lama heli karo.", "noMatchingProducts": "App Store ma soo celin xirmooyin lacag adeeg oo u dhigma.", "noMatchingProductsPlay": "Google Play ma soo celin xirmooyin lacag adeeg oo u dhigma.", + "storeTimedOut": "App Store wakhtigii ma jawaabin. Mar kale isku day.", + "storeTimedOutPlay": "Google Play wakhtigii ma jawaabin. Mar kale isku day.", "purchaseOwnedByAnotherAccount": "Lacagta adeeg ee ku jirta Apple Account-kan waxaa leh akoon kale oo Kilo ah. Isticmaalka, soo gal akoonkaas Kilo.", "purchaseOwnedByAnotherAccountPlay": "Lacagta adeeg ee ku yaal xisaabtan Google Play waxaa leh koonto Kilo oo kale. Isticmaalka, ku saxiix bax koontada Kilo-ga ah." }, diff --git a/apps/mobile/src/i18n/locales/sq.json b/apps/mobile/src/i18n/locales/sq.json index b85de0719e2..2cdac35518d 100644 --- a/apps/mobile/src/i18n/locales/sq.json +++ b/apps/mobile/src/i18n/locales/sq.json @@ -3725,6 +3725,8 @@ "empty": "Paketat e krediteve nuk janë të disponueshme tani.", "noMatchingProducts": "App Store nuk ktheu paketa kreditesh që përputhen.", "noMatchingProductsPlay": "Google Play nuk ktheu paketa kreditesh që përputhen.", + "storeTimedOut": "App Store nuk u përgjigj në kohë. Provo përsëri.", + "storeTimedOutPlay": "Google Play nuk u përgjigj në kohë. Provoni përsëri.", "purchaseOwnedByAnotherAccount": "Kreditet në këtë Apple Account i përkasin një llogarie tjetër Kilo. Hyr në atë llogari Kilo për t'i përdorur.", "purchaseOwnedByAnotherAccountPlay": "Kreditet në këtë llogari Google Play i përkasin një llogarie tjetër Kilo. Hyni në atë llogari Kilo për t'i përdorur." }, diff --git a/apps/mobile/src/i18n/locales/sr.json b/apps/mobile/src/i18n/locales/sr.json index abd887cd544..7e70caf526c 100644 --- a/apps/mobile/src/i18n/locales/sr.json +++ b/apps/mobile/src/i18n/locales/sr.json @@ -3766,6 +3766,8 @@ "empty": "Paketi kredita trenutno nisu dostupni.", "noMatchingProducts": "App Store nije vratio odgovarajuće pakete kredita.", "noMatchingProductsPlay": "Google Play nije vratio odgovarajuće pakete kredita.", + "storeTimedOut": "App Store nije odgovorio na vreme. Pokušaj ponovo.", + "storeTimedOutPlay": "Google Play nije odgovorio na vreme. Pokušajte ponovo.", "purchaseOwnedByAnotherAccount": "Krediti na ovom nalogu Apple Account pripadaju drugom Kilo nalogu. Prijavi se na taj Kilo nalog da ih koristiš.", "purchaseOwnedByAnotherAccountPlay": "Krediti na ovom Google Play nalogu pripadaju drugom Kilo nalogu. Prijavite se na taj Kilo nalog da biste ih koristili." }, diff --git a/apps/mobile/src/i18n/locales/sv.json b/apps/mobile/src/i18n/locales/sv.json index 348cae3d945..1ca8b10475d 100644 --- a/apps/mobile/src/i18n/locales/sv.json +++ b/apps/mobile/src/i18n/locales/sv.json @@ -3725,6 +3725,8 @@ "empty": "Kreditpaket är inte tillgängliga just nu.", "noMatchingProducts": "App Store returnerade inga matchande kreditpaket.", "noMatchingProductsPlay": "Google Play returnerade inga matchande kreditpaket.", + "storeTimedOut": "App Store svarade inte i tid. Försök igen.", + "storeTimedOutPlay": "Google Play svarade inte i tid. Försök igen.", "purchaseOwnedByAnotherAccount": "Krediterna på detta Apple-konto tillhör ett annat Kilo-konto. Logga in på det Kilo-kontot för att använda dem.", "purchaseOwnedByAnotherAccountPlay": "Krediterna på detta Google Play-konto tillhör ett annat Kilo-konto. Logga in på det Kilo-kontot för att använda dem." }, diff --git a/apps/mobile/src/i18n/locales/sw.json b/apps/mobile/src/i18n/locales/sw.json index c1a4f5f786a..10131c19be2 100644 --- a/apps/mobile/src/i18n/locales/sw.json +++ b/apps/mobile/src/i18n/locales/sw.json @@ -3725,6 +3725,8 @@ "empty": "Pakiti za salio hazipatikani kwa sasa.", "noMatchingProducts": "App Store haikurudisha pakiti za salio zinazolingana.", "noMatchingProductsPlay": "Google Play haikurudisha pakiti za salio zinazolingana.", + "storeTimedOut": "App Store haikujibu kwa wakati. Jaribu tena.", + "storeTimedOutPlay": "Google Play haikujibu kwa wakati. Jaribu tena.", "purchaseOwnedByAnotherAccount": "Salio katika Apple Account hii ni ya akaunti nyingine ya Kilo. Ingia kwenye akaunti hiyo ya Kilo ili kulitumia.", "purchaseOwnedByAnotherAccountPlay": "Salio kwenye Akaunti hii ya Google Play ni ya akaunti nyingine ya Kilo. Ingia kwenye akaunti hiyo ya Kilo ili kulitumia." }, diff --git a/apps/mobile/src/i18n/locales/ta.json b/apps/mobile/src/i18n/locales/ta.json index 281c1d688ed..177851b0d58 100644 --- a/apps/mobile/src/i18n/locales/ta.json +++ b/apps/mobile/src/i18n/locales/ta.json @@ -3725,6 +3725,8 @@ "empty": "கிரெடிட் பேக்குகள் இப்போது கிடைக்கவில்லை.", "noMatchingProducts": "App Store பொருந்தும் கிரெடிட் பேக்குகளை வழங்கவில்லை.", "noMatchingProductsPlay": "Google Play பொருந்தும் கிரெடிட் பேக்குகளை வழங்கவில்லை.", + "storeTimedOut": "App Store நேரத்திற்குள் பதிலளிக்கவில்லை. மீண்டும் முயற்சிக்கவும்.", + "storeTimedOutPlay": "Google Play நேரத்திற்குள் பதிலளிக்கவில்லை. மீண்டும் முயற்சிக்கவும்.", "purchaseOwnedByAnotherAccount": "இந்த Apple Account-இல் உள்ள கிரெடிட்கள் வேறொரு Kilo கணக்கைச் சேர்ந்தவை. அவற்றைப் பயன்படுத்த அந்த Kilo கணக்கில் உள்நுழையவும்.", "purchaseOwnedByAnotherAccountPlay": "இந்த Google Play கணக்கில் உள்ள கிரெடிட்கள் வேறொரு Kilo கணக்கைச் சேர்ந்தவை. அவற்றைப் பயன்படுத்த அந்த Kilo கணக்கில் உள்நுழையவும்." }, diff --git a/apps/mobile/src/i18n/locales/te.json b/apps/mobile/src/i18n/locales/te.json index b2c7d76a06f..d4ed89775e1 100644 --- a/apps/mobile/src/i18n/locales/te.json +++ b/apps/mobile/src/i18n/locales/te.json @@ -3725,6 +3725,8 @@ "empty": "క్రెడిట్ ప్యాక్‌లు ప్రస్తుతం అందుబాటులో లేవు.", "noMatchingProducts": "App Store సరిపోలే క్రెడిట్ ప్యాక్‌లను అందించలేదు.", "noMatchingProductsPlay": "Google Play సరిపోలే క్రెడిట్ ప్యాక్‌లను అందించలేదు.", + "storeTimedOut": "App Store సమయానికి స్పందించలేదు. మళ్లీ ప్రయత్నించండి.", + "storeTimedOutPlay": "Google Play సమయానికి స్పందించలేదు. మళ్లీ ప్రయత్నించండి.", "purchaseOwnedByAnotherAccount": "ఈ Apple Accountలోని క్రెడిట్‌లు వేరే Kilo ఖాతాకు చెందుతాయి. వాటిని ఉపయోగించడానికి ఆ Kilo ఖాతాతో సైన్ ఇన్ చేయండి.", "purchaseOwnedByAnotherAccountPlay": "ఈ Google Play ఖాతాలోని క్రెడిట్‌లు వేరే Kilo ఖాతాకు చెందుతాయి. వాటిని ఉపయోగించడానికి ఆ Kilo ఖాతాతో సైన్ ఇన్ చేయండి." }, diff --git a/apps/mobile/src/i18n/locales/th.json b/apps/mobile/src/i18n/locales/th.json index 9184e9beb57..4de1213ed26 100644 --- a/apps/mobile/src/i18n/locales/th.json +++ b/apps/mobile/src/i18n/locales/th.json @@ -3725,6 +3725,8 @@ "empty": "แพ็กเกจเครดิตไม่พร้อมใช้งานในขณะนี้", "noMatchingProducts": "App Store ไม่ได้ส่งแพ็กเกจเครดิตที่ตรงกันกลับมา", "noMatchingProductsPlay": "Google Play ไม่ได้ส่งแพ็กเกจเครดิตที่ตรงกันกลับมา", + "storeTimedOut": "App Store ไม่ได้ตอบสนองภายในเวลาที่กำหนด ลองอีกครั้ง", + "storeTimedOutPlay": "Google Play ไม่ได้ตอบสนองภายในเวลาที่กำหนด ลองอีกครั้ง", "purchaseOwnedByAnotherAccount": "เครดิตใน Apple Account นี้เป็นของบัญชี Kilo อื่น ลงชื่อเข้าใช้บัญชี Kilo นั้นเพื่อใช้งาน", "purchaseOwnedByAnotherAccountPlay": "เครดิตในบัญชี Google Play นี้เป็นของบัญชี Kilo อื่น ลงชื่อเข้าใช้บัญชี Kilo นั้นเพื่อใช้งาน" }, diff --git a/apps/mobile/src/i18n/locales/tr.json b/apps/mobile/src/i18n/locales/tr.json index d0e6ddee409..886f3cde740 100644 --- a/apps/mobile/src/i18n/locales/tr.json +++ b/apps/mobile/src/i18n/locales/tr.json @@ -3725,6 +3725,8 @@ "empty": "Kredi paketleri şu anda kullanılamıyor.", "noMatchingProducts": "App Store eşleşen kredi paketi döndürmedi.", "noMatchingProductsPlay": "Google Play eşleşen kredi paketi döndürmedi.", + "storeTimedOut": "App Store zamanında yanıt vermedi. Tekrar dene.", + "storeTimedOutPlay": "Google Play zamanında yanıt vermedi. Tekrar dene.", "purchaseOwnedByAnotherAccount": "Bu Apple Account üzerindeki krediler farklı bir Kilo hesabına ait. Kullanmak için o Kilo hesabıyla oturum aç.", "purchaseOwnedByAnotherAccountPlay": "Bu Google Play hesabındaki krediler farklı bir Kilo hesabına ait. Kullanmak için o Kilo hesabıyla oturum açın." }, diff --git a/apps/mobile/src/i18n/locales/uk.json b/apps/mobile/src/i18n/locales/uk.json index e750dd34f01..a188841dbe9 100644 --- a/apps/mobile/src/i18n/locales/uk.json +++ b/apps/mobile/src/i18n/locales/uk.json @@ -3807,6 +3807,8 @@ "empty": "Пакети кредитів зараз недоступні.", "noMatchingProducts": "App Store не повернув відповідні пакети кредитів.", "noMatchingProductsPlay": "Google Play не повернув відповідні пакети кредитів.", + "storeTimedOut": "App Store не відповів у час. Спробуйте ще раз.", + "storeTimedOutPlay": "Google Play не відповів у час. Спробуйте ще раз.", "purchaseOwnedByAnotherAccount": "Кредити в цьому Apple Account належать іншому обліковому запису Kilo. Увійдіть у той обліковий запис Kilo, щоб ними користуватися.", "purchaseOwnedByAnotherAccountPlay": "Кредити в цьому обліковому записі Google Play належать іншому обліковому запису Kilo. Увійдіть у той обліковий запис Kilo, щоб ними користуватися." }, diff --git a/apps/mobile/src/i18n/locales/ur.json b/apps/mobile/src/i18n/locales/ur.json index d9d374ce685..f0029b99a16 100644 --- a/apps/mobile/src/i18n/locales/ur.json +++ b/apps/mobile/src/i18n/locales/ur.json @@ -3725,6 +3725,8 @@ "empty": "کریڈٹ پیک اس وقت دستیاب نہیں ہیں۔", "noMatchingProducts": "App Store نے کوئی مماثل کریڈٹ پیک واپس نہیں کیا۔", "noMatchingProductsPlay": "Google Play نے کوئی مماثل کریڈٹ پیک واپس نہیں کیا۔", + "storeTimedOut": "App Store نے وقت پر جواب نہیں دیا۔ دوبارہ کوشش کریں۔", + "storeTimedOutPlay": "Google Play نے وقت پر جواب نہیں دیا۔ دوبارہ کوشش کریں۔", "purchaseOwnedByAnotherAccount": "اس Apple Account کے کریڈٹس کسی دوسرے Kilo اکاؤنٹ سے تعلق رکھتے ہیں۔ انہیں استعمال کرنے کے لیے اسی Kilo اکاؤنٹ میں سائن ان کریں۔", "purchaseOwnedByAnotherAccountPlay": "اس Google Play اکاؤنٹ کے کریڈٹس کسی دوسرے Kilo اکاؤنٹ سے تعلق رکھتے ہیں۔ انہیں استعمال کرنے کے لیے اس Kilo اکاؤنٹ میں سائن ان کریں۔" }, diff --git a/apps/mobile/src/i18n/locales/uz.json b/apps/mobile/src/i18n/locales/uz.json index 6e3a3cfa578..277371a8bf8 100644 --- a/apps/mobile/src/i18n/locales/uz.json +++ b/apps/mobile/src/i18n/locales/uz.json @@ -3725,6 +3725,8 @@ "empty": "Kredit paketlari hozircha mavjud emas.", "noMatchingProducts": "App Store mos keladigan kredit paketlarini qaytarmadi.", "noMatchingProductsPlay": "Google Play mos keladigan kredit paketlarini qaytarmadi.", + "storeTimedOut": "App Store o'z vaqtida javob bermadi. Qayta urinish.", + "storeTimedOutPlay": "Google Play o'z vaqtida javob bermadi. Qayta urinish.", "purchaseOwnedByAnotherAccount": "Bu Apple Account hisobidagi kreditlar boshqa Kilo hisobiga tegishli. Ulardan foydalanish uchun o'sha Kilo hisobiga kiring.", "purchaseOwnedByAnotherAccountPlay": "Bu Google Play hisobidagi kreditlar boshqa Kilo hisobiga tegishli. Ulardan foydalanish uchun o'sha Kilo hisobiga kiring." }, diff --git a/apps/mobile/src/i18n/locales/vi.json b/apps/mobile/src/i18n/locales/vi.json index f3430edb12b..cfa02cd5077 100644 --- a/apps/mobile/src/i18n/locales/vi.json +++ b/apps/mobile/src/i18n/locales/vi.json @@ -3725,6 +3725,8 @@ "empty": "Các gói tín dụng hiện không khả dụng.", "noMatchingProducts": "App Store không trả về gói tín dụng phù hợp nào.", "noMatchingProductsPlay": "Google Play không trả về gói tín dụng phù hợp nào.", + "storeTimedOut": "App Store không phản hồi kịp thời. Thử lại.", + "storeTimedOutPlay": "Google Play không phản hồi kịp thời. Thử lại.", "purchaseOwnedByAnotherAccount": "Tín dụng trên Apple Account này thuộc về một tài khoản Kilo khác. Hãy đăng nhập vào tài khoản Kilo đó để sử dụng.", "purchaseOwnedByAnotherAccountPlay": "Tín dụng trên Tài khoản Google Play này thuộc về một tài khoản Kilo khác. Hãy đăng nhập vào tài khoản Kilo đó để sử dụng." }, diff --git a/apps/mobile/src/i18n/locales/yo.json b/apps/mobile/src/i18n/locales/yo.json index 685e7188bfe..072b06daeee 100644 --- a/apps/mobile/src/i18n/locales/yo.json +++ b/apps/mobile/src/i18n/locales/yo.json @@ -3725,6 +3725,8 @@ "empty": "Àwọn àpò kírẹ́dítì kò sí ní báyìí.", "noMatchingProducts": "App Store kò dá àwọn àpò kírẹ́dítì tó báramu padà.", "noMatchingProductsPlay": "Google Play kò dá àwọn àpò kírẹ́dítì tó báramu padà.", + "storeTimedOut": "App Store kò dáhùn ní àkókò tó yẹ. Tún gbìyànjú.", + "storeTimedOutPlay": "Google Play kò dáhùn ní àkókò tó yẹ. Tún gbìyànjú.", "purchaseOwnedByAnotherAccount": "Kírẹ́dítì lórí Apple Account yìí jẹ́ ti àkọọ́lẹ̀ Kilo mìíràn. Wọlé sí àkọọ́lẹ̀ Kilo yẹn láti lò ó.", "purchaseOwnedByAnotherAccountPlay": "Kírẹ́dítì lori Google Play àkọọ́lẹ̀ yii jẹ ti Kilo àkọọ́lẹ̀ miiran. Wọle si Kilo àkọọ́lẹ̀ yẹn lati lo o." }, diff --git a/apps/mobile/src/i18n/locales/zh-Hans.json b/apps/mobile/src/i18n/locales/zh-Hans.json index 74b837519a5..6cf8ca04bcc 100644 --- a/apps/mobile/src/i18n/locales/zh-Hans.json +++ b/apps/mobile/src/i18n/locales/zh-Hans.json @@ -3725,6 +3725,8 @@ "empty": "目前无法获取额度包。", "noMatchingProducts": "App Store 未返回匹配的额度包。", "noMatchingProductsPlay": "Google Play 未返回匹配的额度包。", + "storeTimedOut": "App Store 未及时响应。请再试一次。", + "storeTimedOutPlay": "Google Play 未及时响应。请再试一次。", "purchaseOwnedByAnotherAccount": "此 Apple Account 上的额度属于另一个 Kilo 账户。请登录该 Kilo 账户以使用。", "purchaseOwnedByAnotherAccountPlay": "此 Google Play 账户上的额度属于另一个 Kilo 账户。请登录该 Kilo 账户以使用。" }, diff --git a/apps/mobile/src/i18n/locales/zh-Hant.json b/apps/mobile/src/i18n/locales/zh-Hant.json index 4e5e3d88e32..905590f2168 100644 --- a/apps/mobile/src/i18n/locales/zh-Hant.json +++ b/apps/mobile/src/i18n/locales/zh-Hant.json @@ -3725,6 +3725,8 @@ "empty": "目前無法取得點數包。", "noMatchingProducts": "App Store 未傳回相符的點數包。", "noMatchingProductsPlay": "Google Play 未傳回相符的點數包。", + "storeTimedOut": "App Store 未及時回應。請再試一次。", + "storeTimedOutPlay": "Google Play 未及時回應。請再試一次。", "purchaseOwnedByAnotherAccount": "此 Apple 帳戶上的點數屬於另一個 Kilo 帳戶。請登入該 Kilo 帳戶以使用。", "purchaseOwnedByAnotherAccountPlay": "此 Google Play 帳戶上的點數屬於另一個 Kilo 帳戶。請登入該 Kilo 帳戶以使用。" }, diff --git a/apps/mobile/src/i18n/locales/zu.json b/apps/mobile/src/i18n/locales/zu.json index 00e557a4704..25c50134cec 100644 --- a/apps/mobile/src/i18n/locales/zu.json +++ b/apps/mobile/src/i18n/locales/zu.json @@ -3725,6 +3725,8 @@ "empty": "Amaphakethe amakhredithi awatholakali njengamanje.", "noMatchingProducts": "I-App Store ayizange ibuyisele amaphakethe amakhredithi ahambisanayo.", "noMatchingProductsPlay": "I-Google Play ayizange ibuyisele amaphakethe amakhredithi ahambisanayo.", + "storeTimedOut": "I-App Store ayizange iphendle ngasikhathi. Zama futhi.", + "storeTimedOutPlay": "I-Google Play ayizange iphendle ngasikhathi. Zama futhi.", "purchaseOwnedByAnotherAccount": "Amakhredithi kule Apple Account angeye-akhawunti ye-Kilo ehlukile. Ngena kuleyo akhawunti ye-Kilo ukuze uwasebenzise.", "purchaseOwnedByAnotherAccountPlay": "Amakhredithi kule akhawunti ye-Google Play angeye-akhawunti ye-Kilo ehlukile. Ngena kuleyo akhawunti ye-Kilo ukuze uwasebenzise." }, diff --git a/apps/mobile/src/lib/credits/store-products-loader.test.ts b/apps/mobile/src/lib/credits/store-products-loader.test.ts index 35c32bf2c66..bc659eef648 100644 --- a/apps/mobile/src/lib/credits/store-products-loader.test.ts +++ b/apps/mobile/src/lib/credits/store-products-loader.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-lines -- one suite covers the loader's copy keys, its catalog diagnostics, and the three store-call outcomes (failure, deadline, zero-match) */ import { describe, expect, it, vi } from 'vitest'; import { @@ -6,11 +7,27 @@ import { loadStoreCreditProducts, NO_MATCHING_CREDIT_PRODUCTS_KEY, NO_MATCHING_CREDIT_PRODUCTS_PLAY_KEY, + STORE_FAILURE_KEY, + STORE_FAILURE_PLAY_KEY, + STORE_TIMEOUT_KEY, + STORE_TIMEOUT_PLAY_KEY, StoreCreditProductsError, } from './store-products-loader'; -import { type BackendStoreCreditProduct } from './store-products'; +import { type BackendStoreCreditProduct, type StoreProductFetchOptions } from './store-products'; +import { isStoreDeadlineError } from '@/lib/iap/store-call-deadline'; import { TELEMETRY_DESCRIPTION_KEY } from '@/lib/telemetry/error-sink'; +type FetchStoreProducts = ( + productSkus: string[], + options?: StoreProductFetchOptions +) => Promise; + +/** A store that never answers: only the deadline settles this call. */ +// eslint-disable-next-line @typescript-eslint/promise-function-async -- a promise that never settles is the scenario under test +function hungStoreCall(): Promise { + return new Promise(() => undefined); +} + const backendProducts: BackendStoreCreditProduct[] = [ { amountUsd: 10, appleProductId: 'credits.usd10.v1', googleProductId: 'credits_usd10' }, { amountUsd: 50, appleProductId: 'credits.usd50.v1', googleProductId: 'credits_usd50' }, @@ -49,12 +66,10 @@ describe('loadStoreCreditProducts', () => { }); expect(loadBackendProductsMock).toHaveBeenCalledTimes(1); - expect(fetchStoreProducts).toHaveBeenCalledWith([ - 'credits.usd10.v1', - 'credits.usd50.v1', - 'credits.usd100.v1', - 'credits.usd500.v1', - ]); + expect(fetchStoreProducts).toHaveBeenCalledWith( + ['credits.usd10.v1', 'credits.usd50.v1', 'credits.usd100.v1', 'credits.usd500.v1'], + { signal: expect.any(AbortSignal) } + ); expect(products).toHaveLength(4); expect(products[0]?.displayPrice).toBe('$10.99'); expect(products[1]?.displayPrice).toBeNull(); @@ -71,15 +86,13 @@ describe('loadStoreCreditProducts', () => { loadBackendProducts: loadBackendProducts(), }); - expect(fetchStoreProducts).toHaveBeenCalledWith([ - 'credits_usd10', - 'credits_usd50', - 'credits_usd100', - 'credits_usd500', - ]); + expect(fetchStoreProducts).toHaveBeenCalledWith( + ['credits_usd10', 'credits_usd50', 'credits_usd100', 'credits_usd500'], + { signal: expect.any(AbortSignal) } + ); }); - it('surfaces the App Store key with the store failure as cause when the store call fails', async () => { + it('surfaces the App Store failure key with the store failure as cause when the store call fails', async () => { const storeError = new Error('Failed to query product for sku'); const failure = await loadStoreCreditProducts({ @@ -89,7 +102,7 @@ describe('loadStoreCreditProducts', () => { }).catch((error: unknown) => error); expect(failure).toBeInstanceOf(StoreCreditProductsError); - expect(failure).toMatchObject({ key: NO_MATCHING_CREDIT_PRODUCTS_KEY }); + expect(failure).toMatchObject({ key: STORE_FAILURE_KEY }); expect((failure as StoreCreditProductsError).cause).toBe(storeError); expect((failure as StoreCreditProductsError).diagnostics).toEqual({ storefront: 'app_store', @@ -101,7 +114,7 @@ describe('loadStoreCreditProducts', () => { }); }); - it('surfaces the Play key with the store failure as cause when the store call fails', async () => { + it('surfaces the Play failure key with the store failure as cause when the store call fails', async () => { const storeError = new Error('Failed to query product for sku'); const failure = await loadStoreCreditProducts({ @@ -111,7 +124,7 @@ describe('loadStoreCreditProducts', () => { }).catch((error: unknown) => error); expect(failure).toBeInstanceOf(StoreCreditProductsError); - expect(failure).toMatchObject({ key: NO_MATCHING_CREDIT_PRODUCTS_PLAY_KEY }); + expect(failure).toMatchObject({ key: STORE_FAILURE_PLAY_KEY }); expect((failure as StoreCreditProductsError).cause).toBe(storeError); expect((failure as StoreCreditProductsError).diagnostics).toEqual({ storefront: 'play', @@ -123,6 +136,98 @@ describe('loadStoreCreditProducts', () => { }); }); + // The deadline is not a store answer, so it must not read as a catalog claim + // and must stay distinguishable from a store that answered with a failure. + async function deadlineFailure( + storefront: 'app_store' | 'play', + fetchStoreProducts: FetchStoreProducts + ) { + vi.useFakeTimers(); + try { + // Attach to the rejection before the clock moves, so the deadline's + // rejection is never unhandled. + const settled = (async (): Promise => { + try { + return await loadStoreCreditProducts({ + storefront, + fetchStoreProducts, + loadBackendProducts: loadBackendProducts(), + }); + } catch (error) { + return error; + } + })(); + // Let the backend answer and the deadline arm before the clock moves. + await vi.advanceTimersByTimeAsync(0); + await vi.advanceTimersByTimeAsync(15_000); + const failure = await settled; + if (!(failure instanceof StoreCreditProductsError)) { + throw new Error('expected the loader to reject with a catalog error'); + } + return failure; + } finally { + vi.useRealTimers(); + } + } + + it('surfaces the App Store timeout key when the store misses the deadline', async () => { + const fetchStoreProducts = vi.fn(hungStoreCall); + + const failure = await deadlineFailure('app_store', fetchStoreProducts); + + expect(failure).toBeInstanceOf(StoreCreditProductsError); + expect(failure.key).toBe(STORE_TIMEOUT_KEY); + expect(isStoreDeadlineError(failure.cause)).toBe(true); + expect(failure.diagnostics).toEqual({ + storefront: 'app_store', + backendPackCount: 4, + storeListingCount: 0, + matchedCount: 0, + requestedProductIds: APPLE_REQUESTED_IDS, + returnedProductIds: [], + }); + // A deadline is a bounded, expected outcome: it reports under its own + // fingerprint as a warning, never as the error a store failure files as. + expect(failure[TELEMETRY_DESCRIPTION_KEY]).toEqual({ + level: 'warning', + fingerprint: ['credit-catalog-query', 'store-timeout', 'app_store'], + tags: { + 'error.subsystem': 'credits', + 'error.operation': 'load-store-products', + 'credits.storefront': 'app_store', + 'credits.outcome': 'store-timeout', + }, + contexts: { + creditCatalogQuery: { + storefront: 'app_store', + backendPackCount: 4, + storeListingCount: 0, + matchedCount: 0, + requestedProductIds: APPLE_REQUESTED_IDS, + returnedProductIds: [], + }, + }, + }); + }); + + it('surfaces the Play timeout key when the store misses the deadline', async () => { + const fetchStoreProducts = vi.fn(hungStoreCall); + + const failure = await deadlineFailure('play', fetchStoreProducts); + + expect(failure.key).toBe(STORE_TIMEOUT_PLAY_KEY); + expect(isStoreDeadlineError(failure.cause)).toBe(true); + }); + + it('aborts the store call it gave up on, so nothing asks the hung store again', async () => { + const fetchStoreProducts = vi.fn(hungStoreCall); + + await deadlineFailure('play', fetchStoreProducts); + + const signal = fetchStoreProducts.mock.calls[0]?.[1]?.signal; + expect(signal?.aborted).toBe(true); + }); + it('surfaces the App Store key with both sides ids when the store prices no pack', async () => { const failure = await loadStoreCreditProducts({ storefront: 'app_store', @@ -197,17 +302,21 @@ describe('loadStoreCreditProducts', () => { }); describe('getStoreUnavailableCopyKeys', () => { - it('names the App Store for the app_store storefront on both lines', () => { + it('names the App Store for the app_store storefront on the title and the catalog body', () => { expect(getStoreUnavailableCopyKeys('app_store')).toEqual({ titleKey: 'kiloPass.productsUnavailable', bodyKey: NO_MATCHING_CREDIT_PRODUCTS_KEY, + failureBodyKey: STORE_FAILURE_KEY, + timeoutBodyKey: STORE_TIMEOUT_KEY, }); }); - it('names Google Play for the play storefront on both lines', () => { + it('names Google Play for the play storefront on the title and the catalog body', () => { expect(getStoreUnavailableCopyKeys('play')).toEqual({ titleKey: 'kiloPass.productsUnavailablePlay', bodyKey: NO_MATCHING_CREDIT_PRODUCTS_PLAY_KEY, + failureBodyKey: STORE_FAILURE_PLAY_KEY, + timeoutBodyKey: STORE_TIMEOUT_PLAY_KEY, }); }); }); diff --git a/apps/mobile/src/lib/credits/store-products-loader.ts b/apps/mobile/src/lib/credits/store-products-loader.ts index 0c9ee4f48b5..20304bdba99 100644 --- a/apps/mobile/src/lib/credits/store-products-loader.ts +++ b/apps/mobile/src/lib/credits/store-products-loader.ts @@ -1,4 +1,4 @@ -import { withStoreDeadline } from '@/lib/iap/store-call-deadline'; +import { isStoreDeadlineError, withStoreDeadline } from '@/lib/iap/store-call-deadline'; import { TELEMETRY_DESCRIPTION_KEY, type TelemetryDescription } from '@/lib/telemetry/error-sink'; import { @@ -6,10 +6,24 @@ import { joinStoreCreditProducts, type StoreCreditProduct, type StoreCreditProductListing, + type StoreProductFetchOptions, } from './store-products'; export const NO_MATCHING_CREDIT_PRODUCTS_KEY = 'credits.noMatchingProducts'; export const NO_MATCHING_CREDIT_PRODUCTS_PLAY_KEY = 'credits.noMatchingProductsPlay'; +/** + * The card body for a store call that failed, per storefront. + * + * Catalog keys, not copy: the screen translates them, and the Kilo Pass copy is + * identical, so reusing its keys keeps `check:i18n` free of a duplicate string. + * The screen's own connection bound renders these too, so both paths say the + * same thing: the store did not answer. + */ +export const STORE_FAILURE_KEY = 'kiloPass.couldNotConnectToAppStore'; +export const STORE_FAILURE_PLAY_KEY = 'kiloPass.couldNotConnectToPlay'; +/** The card body for a store call that missed the deadline, per storefront. */ +export const STORE_TIMEOUT_KEY = 'credits.storeTimedOut'; +export const STORE_TIMEOUT_PLAY_KEY = 'credits.storeTimedOutPlay'; /** The storefront the loader asked, echoed in diagnostics and reports. */ type Storefront = 'app_store' | 'play'; @@ -35,11 +49,12 @@ export type StoreCreditProductsDiagnostics = { * reach the screen, so the screen only ever translates a key from this class. * * The error also declares its own telemetry: a store failure files under an - * error-level fingerprint, and the store answering without pricing any pack — - * an expected, handled outcome the screen shows a card for — files as a warning. - * Both carry {@link StoreCreditProductsDiagnostics} so a report distinguishes a - * store-side pricing gap from a catalog id mismatch or a hung SDK, and the - * caught store error rides along as `cause`. + * error-level fingerprint; the store answering without pricing any pack, and a + * store that missed the call deadline — both expected, handled outcomes the + * screen shows a card for — file as warnings. Each carries + * {@link StoreCreditProductsDiagnostics} so a report distinguishes a store-side + * pricing gap from a catalog id mismatch, a store failure, or a hung SDK, and + * the caught store error rides along as `cause`. */ export class StoreCreditProductsError extends Error { readonly key: string; @@ -64,16 +79,25 @@ export class StoreCreditProductsError extends Error { diagnostics: StoreCreditProductsDiagnostics, cause: unknown ): TelemetryDescription { - const storeAnswered = cause === undefined; - const fingerprint = storeAnswered ? 'store-unavailable' : 'store-error'; + // Three outcomes, told apart by what the store did. No cause: it answered + // and priced nothing. A deadline: it never answered — bounded, expected, + // and retried on the next user attempt, so it is a warning like the + // zero-match answer, under its own fingerprint. Any other cause: it + // answered with a failure, which is the one real error here. + let outcome: 'store-unavailable' | 'store-timeout' | 'store-error' = 'store-error'; + if (cause === undefined) { + outcome = 'store-unavailable'; + } else if (isStoreDeadlineError(cause)) { + outcome = 'store-timeout'; + } return { - level: storeAnswered ? 'warning' : 'error', - fingerprint: ['credit-catalog-query', fingerprint, diagnostics.storefront], + level: outcome === 'store-error' ? 'error' : 'warning', + fingerprint: ['credit-catalog-query', outcome, diagnostics.storefront], tags: { 'error.subsystem': 'credits', 'error.operation': 'load-store-products', 'credits.storefront': diagnostics.storefront, - 'credits.outcome': fingerprint, + 'credits.outcome': outcome, }, contexts: { creditCatalogQuery: { @@ -98,12 +122,16 @@ export function getAuthoredProductsErrorMessageKey(error: unknown): string | nul return error instanceof StoreCreditProductsError ? error.key : null; } -/** The two catalog keys the store-unavailable card renders, per storefront. */ +/** The catalog keys the store-unavailable card renders, per storefront. */ export type StoreUnavailableCopyKeys = { /** Card title: ` products unavailable`. */ titleKey: string; /** Card body for a store the loader found no products for. */ bodyKey: string; + /** Card body for a store call that failed for the store's own reasons. */ + failureBodyKey: string; + /** Card body for a store call that missed the deadline. */ + timeoutBodyKey: string; }; /** @@ -113,6 +141,12 @@ export type StoreUnavailableCopyKeys = { * two separate per-OS branches is what let an iOS build show a Google Play * body under an App Store title. Callers pass the storefront they buy from, * so the store name is chosen exactly once. + * + * The three bodies keep the three outcomes apart: a store that priced no pack + * is a catalog answer, a store that failed to answer is a failure, and a store + * that never answered inside the deadline is a timeout. A timeout must not + * read as a catalog claim, and the failure copy is shared with the screen's + * own connection bound, which means "the store did not answer" too. */ export function getStoreUnavailableCopyKeys( storefront: 'app_store' | 'play' @@ -121,15 +155,33 @@ export function getStoreUnavailableCopyKeys( ? { titleKey: 'kiloPass.productsUnavailablePlay', bodyKey: NO_MATCHING_CREDIT_PRODUCTS_PLAY_KEY, + failureBodyKey: STORE_FAILURE_PLAY_KEY, + timeoutBodyKey: STORE_TIMEOUT_PLAY_KEY, } : { titleKey: 'kiloPass.productsUnavailable', bodyKey: NO_MATCHING_CREDIT_PRODUCTS_KEY, + failureBodyKey: STORE_FAILURE_KEY, + timeoutBodyKey: STORE_TIMEOUT_KEY, }; } +/** + * The authored body key for a store call that did not answer. A store that + * missed the deadline gets the timeout copy and a store that answered with a + * failure gets the failure copy; neither is a catalog claim — only an answer + * that priced no pack is, and that path never reaches here. + */ +function storeCallFailureKey(storefront: Storefront, storeError: unknown): string { + const copy = getStoreUnavailableCopyKeys(storefront); + return isStoreDeadlineError(storeError) ? copy.timeoutBodyKey : copy.failureBodyKey; +} + export async function loadStoreCreditProducts(params: { - fetchStoreProducts: (productSkus: string[]) => Promise; + fetchStoreProducts: ( + productSkus: string[], + options?: StoreProductFetchOptions + ) => Promise; loadBackendProducts: () => Promise; storefront: Storefront; }): Promise { @@ -144,20 +196,27 @@ export async function loadStoreCreditProducts(params: { } let storeProducts: readonly StoreCreditProductListing[] = []; + // Aborted as soon as this call settles without an answer, so a store that + // already missed the deadline is not asked again by whatever retries inside + // `fetchStoreProducts`: the SDK has no cancellation, and a hung store stays + // hung for every further call. + const storeCall = new AbortController(); try { // A store that never answers is worse than one that fails: the screen would // stay on its placeholders and offer no retry. The same deadline the rest of // the flow uses bounds this call, so a hung SDK reads as unavailable. storeProducts = await withStoreDeadline( - params.fetchStoreProducts(productSkus), + params.fetchStoreProducts(productSkus, { signal: storeCall.signal }), 'the credit pack price lookup' ); } catch (storeError) { + storeCall.abort(); // The store SDK's wording is not for the screen: surface a catalog key and // keep the store failure as the cause so reporting can tell a store-side - // outage from a catalog mismatch. + // outage from a catalog mismatch. A deadline keeps its own copy and its own + // report outcome instead of reading as a catalog that priced nothing. throw new StoreCreditProductsError( - getStoreUnavailableCopyKeys(params.storefront).bodyKey, + storeCallFailureKey(params.storefront, storeError), { storefront: params.storefront, backendPackCount: backendProducts.length, diff --git a/apps/mobile/src/lib/credits/store-products.ts b/apps/mobile/src/lib/credits/store-products.ts index d609f6902e1..5d0d495c51b 100644 --- a/apps/mobile/src/lib/credits/store-products.ts +++ b/apps/mobile/src/lib/credits/store-products.ts @@ -17,6 +17,16 @@ export type StoreCreditProductListing = { displayPrice: string; }; +/** + * Options for one store product fetch. + * + * `signal` aborts once the caller's bounded call has settled without an answer. + * A store that already missed the deadline stays silent for every further call, + * and the SDK has no cancellation, so whoever would retry has to check this + * before asking again. + */ +export type StoreProductFetchOptions = { signal?: AbortSignal }; + /** * One backend credit pack joined with the store product that sells it. The * store fields are `null` when the store does not sell that pack: unlike the diff --git a/apps/mobile/src/lib/credits/use-store-credit-products.ts b/apps/mobile/src/lib/credits/use-store-credit-products.ts index 171dce65a04..47870d4db10 100644 --- a/apps/mobile/src/lib/credits/use-store-credit-products.ts +++ b/apps/mobile/src/lib/credits/use-store-credit-products.ts @@ -8,26 +8,28 @@ import { getStoreCreditProductsState, type StoreCreditProduct, type StoreCreditProductListing, + type StoreProductFetchOptions, } from './store-products'; import { getAuthoredProductsErrorMessageKey, loadStoreCreditProducts, + STORE_FAILURE_KEY, + STORE_FAILURE_PLAY_KEY, } from './store-products-loader'; const STORE_CREDIT_PRODUCTS_STALE_TIME_MS = 5 * 60 * 1000; // Fixed bound on the store connection handshake — raise if real // devices routinely need longer than this to connect. const STORE_CONNECTION_TIMEOUT_MS = 8000; -// Catalog keys, not copy: the screen translates them, and the Kilo Pass copy is -// identical, so reusing its keys keeps `check:i18n` free of a duplicate string. -const APP_STORE_CONNECTION_TIMEOUT_KEY = 'kiloPass.couldNotConnectToAppStore'; -const PLAY_CONNECTION_TIMEOUT_KEY = 'kiloPass.couldNotConnectToPlay'; export type StoreCreditProductsOptions = { /** Whether the store connection (from the IAP owner) is established. */ connected: boolean; /** Fetches store SKUs. Injected by the IAP owner so this module never imports `expo-iap`. */ - fetchStoreProducts: (productSkus: string[]) => Promise; + fetchStoreProducts: ( + productSkus: string[], + options?: StoreProductFetchOptions + ) => Promise; /** * Restores the IAP owner's store connection. * @@ -83,7 +85,7 @@ export function useStoreCreditProducts(options: StoreCreditProductsOptions) { // banner shows can never come from two different platform branches. const storefront = getCreditStorefront(); const storeConnectionTimeoutKey = - storefront === 'play' ? PLAY_CONNECTION_TIMEOUT_KEY : APP_STORE_CONNECTION_TIMEOUT_KEY; + storefront === 'play' ? STORE_FAILURE_PLAY_KEY : STORE_FAILURE_KEY; const productsQuery = useQuery({ queryKey: ['credits', 'store-products', userId], diff --git a/apps/mobile/src/lib/iap/store-call-deadline.ts b/apps/mobile/src/lib/iap/store-call-deadline.ts index ef27232f81e..fd5974bbc0e 100644 --- a/apps/mobile/src/lib/iap/store-call-deadline.ts +++ b/apps/mobile/src/lib/iap/store-call-deadline.ts @@ -24,6 +24,16 @@ class StoreDeadlineError extends Error { } } +/** + * True when the caught value is the deadline itself, not a store that answered + * with a failure. Callers keep the two apart: a deadline is a bounded, expected + * outcome the screen reports its own way, and it must not be followed by more + * calls to the same store. + */ +export function isStoreDeadlineError(error: unknown): error is StoreDeadlineError { + return error instanceof StoreDeadlineError; +} + /** * Bounds a store call so a hung SDK never holds a recovery pass open. *