diff --git a/docs/how-to-rate.md b/docs/how-to-rate.md index 2ac31ddcf8..abece4348a 100644 --- a/docs/how-to-rate.md +++ b/docs/how-to-rate.md @@ -1,11 +1,10 @@ # How to Rate ***Super Productivity*** -### Why only 5-star reviews help (unfortunately) +## How ratings affect app discoverability -Most app store algorithms and ranking systems heavily weight 5-star ratings when calculating overall visibility and trustworthiness. -Lower ratings, even if positive, dilute the average score and reduce how often the app is recommended or featured. +App store ranking algorithms favor apps with higher average ratings. For a small project, even a few low ratings can have an outsized effect on the average and on how often the app is recommended or featured. -This leads to the weird situation that a well-intentioned and fair 4-star rating (after all, who is perfect?), *does* actually hurt. +If you've found Super Productivity useful, an honest rating or short review helps the project reach more people. ## 🪟 Windows (Microsoft Store) @@ -28,25 +27,21 @@ This leads to the weird situation that a well-intentioned and fair 4-star rating ## 🖥️ macOS (Mac App Store) -1. Open the **App Store** on your Mac -2. Search for **Super Productivity** -3. Click the Super Productivity result to view its page -4. Scroll to **Ratings & Reviews** -5. Click the number of ⭐ stars you want to give -6. (Optional) Write a review -7. Click **Send** +1. Open the [App Store page](https://apps.apple.com/app/id1482572463) on your Mac +2. Scroll to **Ratings & Reviews** +3. Click the number of ⭐ stars you want to give +4. (Optional) Write a review +5. Click **Send** --- ## 🍎 iOS (App Store) -1. Open the **App Store** on your iPhone or iPad -2. Search for **Super Productivity** -3. Tap the Super Productivity result to view its page -4. Scroll to **Ratings & Reviews** -5. Tap the number of ⭐ stars you want to give -6. (Optional) Tap **Write a Review** -7. Tap **Send** +1. Open the [App Store page](https://apps.apple.com/app/id1482572463) on your iPhone or iPad +2. Scroll to **Ratings & Reviews** +3. Tap the number of ⭐ stars you want to give +4. (Optional) Tap **Write a Review** +5. Tap **Send** --- @@ -74,9 +69,9 @@ This leads to the weird situation that a well-intentioned and fair 4-star rating --- -# alternativeto.net +## 🌐 alternativeto.net -1. Go to [webpage](https://alternativeto.net/software/super-productivity/about/) +1. Go to [the AlternativeTo page](https://alternativeto.net/software/super-productivity/about/) 2. Scroll to "Comments and Reviews" 3. Click on "Post comment/review" 4. Write a review @@ -84,7 +79,8 @@ This leads to the weird situation that a well-intentioned and fair 4-star rating --- -# Other places to leave reviews +## Other places that help the project +- ⭐ Star us on GitHub: https://github.com/super-productivity/super-productivity - https://www.producthunt.com/products/super-productivity - https://www.pling.com/p/1352584/ diff --git a/src/app/core/persistence/storage-keys.const.ts b/src/app/core/persistence/storage-keys.const.ts index ce81ab1022..c5060d1c53 100644 --- a/src/app/core/persistence/storage-keys.const.ts +++ b/src/app/core/persistence/storage-keys.const.ts @@ -12,6 +12,7 @@ export enum DB { export enum LS { APP_START_COUNT = 'APP_START_COUNT', APP_START_COUNT_LAST_START_DAY = 'APP_START_COUNT_LAST_START_DAY', + RATE_DIALOG_STATE = 'SUP_RATE_DIALOG_STATE', LAST_LOCAL_SYNC_MODEL_CHANGE = 'SUP_LAST_LOCAL_SYNC_MODEL_CHANGE', LOCAL_UI_HELPER = 'SUP_UI_HELPER', diff --git a/src/app/core/startup/startup.service.spec.ts b/src/app/core/startup/startup.service.spec.ts index 2158dae5d7..9733691444 100644 --- a/src/app/core/startup/startup.service.spec.ts +++ b/src/app/core/startup/startup.service.spec.ts @@ -65,6 +65,7 @@ describe('StartupService', () => { const snackServiceSpy = jasmine.createSpyObj('SnackService', ['open']); const matDialogSpy = jasmine.createSpyObj('MatDialog', ['open']); + matDialogSpy.open.and.returnValue({ afterClosed: () => of(undefined) }); const pluginServiceSpy = jasmine.createSpyObj('PluginService', ['initializePlugins']); pluginServiceSpy.initializePlugins.and.returnValue(Promise.resolve()); @@ -169,22 +170,36 @@ describe('StartupService', () => { describe('_handleAppStartRating (private, tested via init)', () => { it('should increment app start count on new day', () => { - // Set up initial state - different day (localStorage.getItem as jasmine.Spy).and.callFake((key: string) => { if (key === LS.APP_START_COUNT) return '5'; - if (key === LS.APP_START_COUNT_LAST_START_DAY) return '2026-01-04'; // Different day + if (key === LS.APP_START_COUNT_LAST_START_DAY) return '2026-01-04'; return null; }); - // Call the private method via reflection for unit testing (service as any)._handleAppStartRating(); expect(localStorage.setItem).toHaveBeenCalledWith(LS.APP_START_COUNT, '6'); }); - it('should show rating dialog at 32 app starts', () => { + it('should not double-increment count on the dialog trigger day', () => { (localStorage.getItem as jasmine.Spy).and.callFake((key: string) => { - if (key === LS.APP_START_COUNT) return '32'; + if (key === LS.APP_START_COUNT) return '31'; + if (key === LS.APP_START_COUNT_LAST_START_DAY) return '2026-01-04'; + return null; + }); + + (service as any)._handleAppStartRating(); + + const incrementCalls = (localStorage.setItem as jasmine.Spy).calls + .allArgs() + .filter(([k]) => k === LS.APP_START_COUNT); + expect(incrementCalls.length).toBe(1); + expect(incrementCalls[0][1]).toBe('32'); + }); + + it('should show rating dialog at the day-32 tier on a fresh state', () => { + (localStorage.getItem as jasmine.Spy).and.callFake((key: string) => { + if (key === LS.APP_START_COUNT) return '31'; if (key === LS.APP_START_COUNT_LAST_START_DAY) return '2026-01-04'; return null; }); @@ -194,10 +209,12 @@ describe('StartupService', () => { expect(matDialog.open).toHaveBeenCalled(); }); - it('should show rating dialog at 96 app starts', () => { + it('should show rating dialog at the day-96 tier when previously shown at day 32', () => { (localStorage.getItem as jasmine.Spy).and.callFake((key: string) => { - if (key === LS.APP_START_COUNT) return '96'; + if (key === LS.APP_START_COUNT) return '95'; if (key === LS.APP_START_COUNT_LAST_START_DAY) return '2026-01-04'; + if (key === LS.RATE_DIALOG_STATE) + return JSON.stringify({ lastShownAppStartDay: 32, permanentOptOut: false }); return null; }); @@ -206,10 +223,26 @@ describe('StartupService', () => { expect(matDialog.open).toHaveBeenCalled(); }); - it('should not show rating dialog at other counts', () => { + it('should not show rating dialog if already shown at the current tier', () => { (localStorage.getItem as jasmine.Spy).and.callFake((key: string) => { - if (key === LS.APP_START_COUNT) return '50'; + if (key === LS.APP_START_COUNT) return '49'; if (key === LS.APP_START_COUNT_LAST_START_DAY) return '2026-01-04'; + if (key === LS.RATE_DIALOG_STATE) + return JSON.stringify({ lastShownAppStartDay: 32, permanentOptOut: false }); + return null; + }); + + (service as any)._handleAppStartRating(); + + expect(matDialog.open).not.toHaveBeenCalled(); + }); + + it('should not show rating dialog when permanentOptOut is true', () => { + (localStorage.getItem as jasmine.Spy).and.callFake((key: string) => { + if (key === LS.APP_START_COUNT) return '95'; + if (key === LS.APP_START_COUNT_LAST_START_DAY) return '2026-01-04'; + if (key === LS.RATE_DIALOG_STATE) + return JSON.stringify({ lastShownAppStartDay: 32, permanentOptOut: true }); return null; }); diff --git a/src/app/core/startup/startup.service.ts b/src/app/core/startup/startup.service.ts index 847a3ad7d8..a2955d4fad 100644 --- a/src/app/core/startup/startup.service.ts +++ b/src/app/core/startup/startup.service.ts @@ -21,6 +21,12 @@ import { isOnline$ } from '../../util/is-online'; import { LS } from '../persistence/storage-keys.const'; import { getDbDateStr } from '../../util/get-db-date-str'; import { DialogPleaseRateComponent } from '../../features/dialog-please-rate/dialog-please-rate.component'; +import { + applyRateDialogResult, + loadRateDialogState, + saveRateDialogState, + shouldShowRateDialog, +} from '../../features/dialog-please-rate/rate-dialog-state'; import { map, take } from 'rxjs/operators'; import { combineLatest } from 'rxjs'; import { Store } from '@ngrx/store'; @@ -365,17 +371,30 @@ export class StartupService { } private _handleAppStartRating(): void { - const appStarts = +(localStorage.getItem(LS.APP_START_COUNT) || 0); const lastStartDay = localStorage.getItem(LS.APP_START_COUNT_LAST_START_DAY); const todayStr = getDbDateStr(); - if (appStarts === 32 || appStarts === 96) { - this._matDialog.open(DialogPleaseRateComponent); - localStorage.setItem(LS.APP_START_COUNT, (appStarts + 1).toString()); - } + let appStarts = +(localStorage.getItem(LS.APP_START_COUNT) || 0); if (lastStartDay !== todayStr) { - localStorage.setItem(LS.APP_START_COUNT, (appStarts + 1).toString()); + appStarts += 1; + localStorage.setItem(LS.APP_START_COUNT, appStarts.toString()); localStorage.setItem(LS.APP_START_COUNT_LAST_START_DAY, todayStr); } + + const state = loadRateDialogState(); + if (!shouldShowRateDialog(state, appStarts)) { + return; + } + this._matDialog + .open(DialogPleaseRateComponent) + .afterClosed() + .subscribe((result) => { + const next = applyRateDialogResult( + loadRateDialogState(), + result ?? null, + appStarts, + ); + saveRateDialogState(next); + }); } private async _initPlugins(): Promise { diff --git a/src/app/features/dialog-please-rate/dialog-please-rate.component.html b/src/app/features/dialog-please-rate/dialog-please-rate.component.html index 1f2baeedeb..db997337ef 100644 --- a/src/app/features/dialog-please-rate/dialog-please-rate.component.html +++ b/src/app/features/dialog-please-rate/dialog-please-rate.component.html @@ -1,28 +1,106 @@ -

{{ T.F.D_RATE.TITLE | translate }}

+@if (view() === 'main') { +

{{ T.F.D_RATE.TITLE | translate }}

- -
+

-

+

-
+ star + {{ cta.labelKey | translate }} + open_in_new + + +
+
- - - + + + + + +} @else { +

{{ T.F.D_RATE.FEEDBACK_TITLE | translate }}

+ + + + + + + + +} diff --git a/src/app/features/dialog-please-rate/dialog-please-rate.component.scss b/src/app/features/dialog-please-rate/dialog-please-rate.component.scss new file mode 100644 index 0000000000..ce947bb61b --- /dev/null +++ b/src/app/features/dialog-please-rate/dialog-please-rate.component.scss @@ -0,0 +1,110 @@ +:host { + display: block; + max-width: 440px; +} + +mat-dialog-content { + p { + margin: 0 0 12px; + } +} + +.action-list { + display: flex; + flex-direction: column; + gap: 8px; + margin-top: 20px; + margin-bottom: 4px; +} + +.action-item { + display: flex; + align-items: center; + gap: 12px; + width: 100%; + min-height: 56px; + padding: 10px 14px; + border: 1px solid rgba(127, 127, 127, 0.3); + border-radius: 8px; + background: transparent; + color: inherit; + font: inherit; + font-size: 14px; + text-align: left; + text-decoration: none; + cursor: pointer; + transition: + background-color 0.15s, + border-color 0.15s; + + &:hover { + background-color: rgba(127, 127, 127, 0.08); + border-color: rgba(127, 127, 127, 0.5); + } + + &:focus-visible { + outline: 2px solid var(--c-accent); + outline-offset: 2px; + } +} + +.action-item-icon { + flex-shrink: 0; + opacity: 0.85; +} + +.action-item-text { + flex: 1 1 auto; + display: flex; + flex-direction: column; + gap: 2px; + line-height: 1.3; + + small { + font-size: 12px; + opacity: 0.7; + } +} + +.action-item-trailing { + flex-shrink: 0; + font-size: 18px; + width: 18px; + height: 18px; + opacity: 0.5; +} + +.action-item--primary { + .action-item-icon { + color: #f9a825; + opacity: 1; + font-variation-settings: + 'FILL' 1, + 'wght' 400, + 'GRAD' 0, + 'opsz' 24; + } + + .action-item-text { + font-weight: 500; + } +} + +.footer-actions { + display: flex; + align-items: center; + gap: 4px; +} + +.spacer { + flex: 1 1 auto; +} + +.opt-out-link { + font-size: 12px; + opacity: 0.65; + + &:hover { + opacity: 1; + } +} diff --git a/src/app/features/dialog-please-rate/dialog-please-rate.component.ts b/src/app/features/dialog-please-rate/dialog-please-rate.component.ts index d85ce562ca..d8dcbb0c72 100644 --- a/src/app/features/dialog-please-rate/dialog-please-rate.component.ts +++ b/src/app/features/dialog-please-rate/dialog-please-rate.component.ts @@ -1,14 +1,21 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core'; import { MatDialogActions, - MatDialogClose, MatDialogContent, + MatDialogRef, MatDialogTitle, } from '@angular/material/dialog'; import { T } from '../../t.const'; -import { MatAnchor, MatButton } from '@angular/material/button'; +import { MatButton } from '@angular/material/button'; import { TranslatePipe } from '@ngx-translate/core'; import { MatIcon } from '@angular/material/icon'; +import { + CONTRIBUTING_URL, + DISCUSSIONS_URL, + RateDialogResult, + buildFeedbackMailto, + getPrimaryCta, +} from './rate-dialog-state'; @Component({ selector: 'dialog-please-rate', @@ -19,24 +26,32 @@ import { MatIcon } from '@angular/material/icon'; MatDialogActions, MatButton, MatIcon, - MatDialogClose, - MatAnchor, TranslatePipe, ], templateUrl: './dialog-please-rate.component.html', + styleUrl: './dialog-please-rate.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, }) export class DialogPleaseRateComponent { - protected readonly T = T; + private readonly _dialogRef = + inject>(MatDialogRef); - // IS_ELECTRON = IS_ELECTRON; - // IS_MAC = /Mac|iPod|iPhone|iPad/.test(navigator.platform); - // IS_WINDOWS = /Win32|Win64|Windows/.test(navigator.platform); - // IS_LINUX = /Linux/.test(navigator.platform); - // - // // For Ubuntu or GNOME: - // IS_UBUNTU = this.IS_LINUX && /Ubuntu/i.test(navigator.userAgent); - // IS_GNOME = this.IS_LINUX && /gnome/i.test(navigator.userAgent); - // IS_SNAP = IS_ELECTRON && window.ea.isSnap(); - // IS_ANDROID_WEBVIEW = IS_ANDROID_WEB_VIEW; + protected readonly T = T; + protected readonly view = signal<'main' | 'feedback'>('main'); + protected readonly cta = getPrimaryCta(); + protected readonly mailtoUrl = buildFeedbackMailto(); + protected readonly discussionsUrl = DISCUSSIONS_URL; + protected readonly contributingUrl = CONTRIBUTING_URL; + + protected showFeedback(): void { + this.view.set('feedback'); + } + + protected showMain(): void { + this.view.set('main'); + } + + protected close(result: RateDialogResult): void { + this._dialogRef.close(result); + } } diff --git a/src/app/features/dialog-please-rate/rate-dialog-state.spec.ts b/src/app/features/dialog-please-rate/rate-dialog-state.spec.ts new file mode 100644 index 0000000000..3bdb5c2347 --- /dev/null +++ b/src/app/features/dialog-please-rate/rate-dialog-state.spec.ts @@ -0,0 +1,143 @@ +import { + RateDialogState, + applyRateDialogResult, + loadRateDialogState, + saveRateDialogState, + shouldShowRateDialog, +} from './rate-dialog-state'; +import { LS } from '../../core/persistence/storage-keys.const'; + +describe('rate-dialog-state', () => { + describe('shouldShowRateDialog', () => { + const fresh: RateDialogState = { lastShownAppStartDay: 0, permanentOptOut: false }; + + it('does not show before day 32 on a fresh state', () => { + expect(shouldShowRateDialog(fresh, 1)).toBe(false); + expect(shouldShowRateDialog(fresh, 31)).toBe(false); + }); + + it('shows at day 32 on a fresh state', () => { + expect(shouldShowRateDialog(fresh, 32)).toBe(true); + }); + + it('shows again at day 96 after first tier dismissal', () => { + const afterFirst: RateDialogState = { + lastShownAppStartDay: 32, + permanentOptOut: false, + }; + expect(shouldShowRateDialog(afterFirst, 33)).toBe(false); + expect(shouldShowRateDialog(afterFirst, 95)).toBe(false); + expect(shouldShowRateDialog(afterFirst, 96)).toBe(true); + }); + + it('does not show again after the second tier (96)', () => { + const afterSecond: RateDialogState = { + lastShownAppStartDay: 96, + permanentOptOut: false, + }; + expect(shouldShowRateDialog(afterSecond, 97)).toBe(false); + expect(shouldShowRateDialog(afterSecond, 1000)).toBe(false); + }); + + it('never shows when permanentOptOut is true', () => { + const optedOut: RateDialogState = { + lastShownAppStartDay: 0, + permanentOptOut: true, + }; + expect(shouldShowRateDialog(optedOut, 32)).toBe(false); + expect(shouldShowRateDialog(optedOut, 96)).toBe(false); + }); + + it('does not show on the same start day it was last shown', () => { + const sameDay: RateDialogState = { + lastShownAppStartDay: 32, + permanentOptOut: false, + }; + expect(shouldShowRateDialog(sameDay, 32)).toBe(false); + }); + }); + + describe('applyRateDialogResult', () => { + const seen32: RateDialogState = { lastShownAppStartDay: 32, permanentOptOut: false }; + + it('sets permanentOptOut on rate', () => { + const next = applyRateDialogResult(seen32, 'rate', 33); + expect(next).toEqual({ lastShownAppStartDay: 33, permanentOptOut: true }); + }); + + it('sets permanentOptOut on feedback', () => { + const next = applyRateDialogResult(seen32, 'feedback', 33); + expect(next).toEqual({ lastShownAppStartDay: 33, permanentOptOut: true }); + }); + + it('sets permanentOptOut on never', () => { + const next = applyRateDialogResult(seen32, 'never', 33); + expect(next).toEqual({ lastShownAppStartDay: 33, permanentOptOut: true }); + }); + + it('only updates lastShownAppStartDay on later (no permanent opt-out yet)', () => { + const next = applyRateDialogResult(seen32, 'later', 33); + expect(next).toEqual({ lastShownAppStartDay: 33, permanentOptOut: false }); + }); + + it('only updates lastShownAppStartDay on null (ESC / backdrop)', () => { + const next = applyRateDialogResult(seen32, null, 33); + expect(next).toEqual({ lastShownAppStartDay: 33, permanentOptOut: false }); + }); + + it('two later clicks across tiers result in no further prompts (implicit permanent stop)', () => { + const fresh: RateDialogState = { lastShownAppStartDay: 0, permanentOptOut: false }; + const afterFirstLater = applyRateDialogResult(fresh, 'later', 32); + expect(shouldShowRateDialog(afterFirstLater, 96)).toBe(true); + const afterSecondLater = applyRateDialogResult(afterFirstLater, 'later', 96); + expect(shouldShowRateDialog(afterSecondLater, 1000)).toBe(false); + }); + }); + + describe('persistence', () => { + let store: { [key: string]: string }; + + beforeEach(() => { + store = {}; + spyOn(localStorage, 'getItem').and.callFake((k: string) => store[k] ?? null); + spyOn(localStorage, 'setItem').and.callFake((k: string, v: string) => { + store[k] = v; + }); + }); + + it('returns default state when nothing is stored', () => { + expect(loadRateDialogState()).toEqual({ + lastShownAppStartDay: 0, + permanentOptOut: false, + }); + }); + + it('round-trips a state object', () => { + saveRateDialogState({ lastShownAppStartDay: 96, permanentOptOut: true }); + expect(localStorage.setItem).toHaveBeenCalledWith( + LS.RATE_DIALOG_STATE, + JSON.stringify({ lastShownAppStartDay: 96, permanentOptOut: true }), + ); + expect(loadRateDialogState()).toEqual({ + lastShownAppStartDay: 96, + permanentOptOut: true, + }); + }); + + it('falls back to defaults on malformed JSON', () => { + store[LS.RATE_DIALOG_STATE] = '{not-json'; + expect(loadRateDialogState()).toEqual({ + lastShownAppStartDay: 0, + permanentOptOut: false, + }); + }); + + it('coerces missing or wrong-type fields to defaults', () => { + store[LS.RATE_DIALOG_STATE] = JSON.stringify({ lastShownAppStartDay: 'oops' }); + expect(loadRateDialogState()).toEqual({ + lastShownAppStartDay: 0, + permanentOptOut: false, + }); + }); + }); +}); diff --git a/src/app/features/dialog-please-rate/rate-dialog-state.ts b/src/app/features/dialog-please-rate/rate-dialog-state.ts new file mode 100644 index 0000000000..813bc1d79a --- /dev/null +++ b/src/app/features/dialog-please-rate/rate-dialog-state.ts @@ -0,0 +1,109 @@ +import { LS } from '../../core/persistence/storage-keys.const'; +import { IS_ANDROID_WEB_VIEW } from '../../util/is-android-web-view'; +import { IS_IOS } from '../../util/is-ios'; +import { IS_ELECTRON } from '../../app.constants'; +import { getAppVersionStr } from '../../util/get-app-version-str'; + +// Device-local only. localStorage keys are implicitly excluded from sync exports. +// Length of TRIGGER_TIERS is the prompt cap: at most one prompt per tier, ever. +// Adding a third entry breaks the "don't be annoying" two-prompts-max guarantee. +const TRIGGER_TIERS = [32, 96] as const; + +const MAINTAINER_EMAIL = 'contact@super-productivity.com'; +const PLAY_STORE_URL = + 'https://play.google.com/store/apps/details?id=com.superproductivity.superproductivity'; +const APP_STORE_URL = 'https://apps.apple.com/app/id1482572463'; +const HOW_TO_RATE_URL = + 'https://github.com/super-productivity/super-productivity/blob/master/docs/how-to-rate.md'; +export const DISCUSSIONS_URL = + 'https://github.com/super-productivity/super-productivity/discussions/new'; +export const CONTRIBUTING_URL = + 'https://github.com/super-productivity/super-productivity/blob/master/CONTRIBUTING.md'; + +export interface RateDialogState { + lastShownAppStartDay: number; + permanentOptOut: boolean; +} + +export type RateDialogResult = 'rate' | 'feedback' | 'later' | 'never'; + +const DEFAULT_STATE: RateDialogState = { + lastShownAppStartDay: 0, + permanentOptOut: false, +}; + +export const loadRateDialogState = (): RateDialogState => { + try { + const raw = localStorage.getItem(LS.RATE_DIALOG_STATE); + if (!raw) return { ...DEFAULT_STATE }; + const parsed = JSON.parse(raw) as Partial; + return { + lastShownAppStartDay: + typeof parsed.lastShownAppStartDay === 'number' ? parsed.lastShownAppStartDay : 0, + permanentOptOut: parsed.permanentOptOut === true, + }; + } catch { + return { ...DEFAULT_STATE }; + } +}; + +export const saveRateDialogState = (state: RateDialogState): void => { + localStorage.setItem(LS.RATE_DIALOG_STATE, JSON.stringify(state)); +}; + +export const shouldShowRateDialog = ( + state: RateDialogState, + currentAppStarts: number, +): boolean => { + if (state.permanentOptOut) return false; + if (currentAppStarts <= state.lastShownAppStartDay) return false; + const nextTier = TRIGGER_TIERS.find((t) => t > state.lastShownAppStartDay); + return nextTier !== undefined && currentAppStarts >= nextTier; +}; + +export const applyRateDialogResult = ( + state: RateDialogState, + result: RateDialogResult | null, + currentAppStarts: number, +): RateDialogState => { + // null = ESC / backdrop close. Treat as silent dismiss for cadence purposes — + // do not pester again until the next tier — but never trigger permanent opt-out. + if (result === 'rate' || result === 'feedback' || result === 'never') { + return { lastShownAppStartDay: currentAppStarts, permanentOptOut: true }; + } + return { ...state, lastShownAppStartDay: currentAppStarts }; +}; + +export interface PrimaryCta { + labelKey: string; + url: string; +} + +export const getPrimaryCta = (): PrimaryCta => { + if (IS_ANDROID_WEB_VIEW) { + return { labelKey: 'F.D_RATE.BTN_RATE_PLAY_STORE', url: PLAY_STORE_URL }; + } + if (IS_IOS) { + return { labelKey: 'F.D_RATE.BTN_RATE_APP_STORE', url: APP_STORE_URL }; + } + return { labelKey: 'F.D_RATE.A_HOW', url: HOW_TO_RATE_URL }; +}; + +const getPlatformLabel = (): string => { + if (IS_IOS) return 'iOS'; + if (IS_ANDROID_WEB_VIEW) return 'Android'; + if (IS_ELECTRON) { + const ua = navigator.userAgent; + if (/Mac|Macintosh/.test(ua)) return 'Electron · macOS'; + if (/Windows/.test(ua)) return 'Electron · Windows'; + if (/Linux/.test(ua)) return 'Electron · Linux'; + return 'Electron'; + } + return 'Web'; +}; + +export const buildFeedbackMailto = (): string => { + const subject = 'Super Productivity feedback'; + const body = `What I'd like to share:\n\n\n---\nApp version: ${getAppVersionStr()}\nPlatform: ${getPlatformLabel()}`; + return `mailto:${MAINTAINER_EMAIL}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`; +}; diff --git a/src/app/t.const.ts b/src/app/t.const.ts index 73afda50a1..c4a6aee423 100644 --- a/src/app/t.const.ts +++ b/src/app/t.const.ts @@ -221,6 +221,18 @@ const T = { D_RATE: { A_HOW: 'F.D_RATE.A_HOW', BTN_DONT_BOTHER: 'F.D_RATE.BTN_DONT_BOTHER', + BTN_FEEDBACK: 'F.D_RATE.BTN_FEEDBACK', + BTN_LATER: 'F.D_RATE.BTN_LATER', + BTN_RATE_APP_STORE: 'F.D_RATE.BTN_RATE_APP_STORE', + BTN_RATE_PLAY_STORE: 'F.D_RATE.BTN_RATE_PLAY_STORE', + FEEDBACK_BACK: 'F.D_RATE.FEEDBACK_BACK', + FEEDBACK_CONTRIBUTE: 'F.D_RATE.FEEDBACK_CONTRIBUTE', + FEEDBACK_CONTRIBUTE_DESC: 'F.D_RATE.FEEDBACK_CONTRIBUTE_DESC', + FEEDBACK_PRIVATE: 'F.D_RATE.FEEDBACK_PRIVATE', + FEEDBACK_PRIVATE_DESC: 'F.D_RATE.FEEDBACK_PRIVATE_DESC', + FEEDBACK_PUBLIC: 'F.D_RATE.FEEDBACK_PUBLIC', + FEEDBACK_PUBLIC_DESC: 'F.D_RATE.FEEDBACK_PUBLIC_DESC', + FEEDBACK_TITLE: 'F.D_RATE.FEEDBACK_TITLE', TITLE: 'F.D_RATE.TITLE', TXT: 'F.D_RATE.TXT', }, diff --git a/src/assets/i18n/ar.json b/src/assets/i18n/ar.json index 25b04fac18..c169779427 100644 --- a/src/assets/i18n/ar.json +++ b/src/assets/i18n/ar.json @@ -171,10 +171,22 @@ } }, "D_RATE": { - "A_HOW": "كيف وأين يتم التقييم", - "BTN_DONT_BOTHER": "لا تزعجني مرة أخرى", - "TITLE": "🙈 من فضلك سامحنا ، لكن ...", - "TXT": "ستساعد المشروع بشكل كبير من خلال منحه تقييما جيدا ، إذا كنت ترغب في ذلك!" + "A_HOW": "كيفية التقييم", + "BTN_DONT_BOTHER": "لا تسأل مرة أخرى", + "BTN_FEEDBACK": "إرسال ملاحظات", + "BTN_LATER": "ربما لاحقًا", + "BTN_RATE_APP_STORE": "قيّم على App Store", + "BTN_RATE_PLAY_STORE": "قيّم على Play Store", + "FEEDBACK_BACK": "رجوع", + "FEEDBACK_CONTRIBUTE": "ساهم في المشروع", + "FEEDBACK_CONTRIBUTE_DESC": "البرمجة، التصميم، الترجمة وغير ذلك", + "FEEDBACK_PRIVATE": "راسل المطوّر", + "FEEDBACK_PRIVATE_DESC": "أرسل رسالة خاصة", + "FEEDBACK_PUBLIC": "انشر على GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "يستطيع الآخرون رؤيتها والرد", + "FEEDBACK_TITLE": "كيف تحب أن تساعد؟", + "TITLE": "هل تستمتع باستخدام Super Productivity؟", + "TXT": "إنه مشروع مجاني ومفتوح المصدر صنعه هواة — بدون تتبّع وبدون إعلانات. تقييم أو رسالة قصيرة تساعد المزيد من الناس على اكتشافه." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/cs.json b/src/assets/i18n/cs.json index 9fc50016ba..9fd6efc2f1 100644 --- a/src/assets/i18n/cs.json +++ b/src/assets/i18n/cs.json @@ -194,10 +194,22 @@ } }, "D_RATE": { - "A_HOW": "Jak a kde hodnotit", - "BTN_DONT_BOTHER": "Znovu mě neobtěžujte", - "TITLE": "🙈 Prosím, odpusťte nám, ale...", - "TXT": "Projektu nesmírně pomůžete udělením dobrého hodnocení, pokud se vám líbí!" + "A_HOW": "Jak hodnotit", + "BTN_DONT_BOTHER": "Příště se neptat", + "BTN_FEEDBACK": "Poslat zpětnou vazbu", + "BTN_LATER": "Možná později", + "BTN_RATE_APP_STORE": "Ohodnotit v App Store", + "BTN_RATE_PLAY_STORE": "Ohodnotit v Play Store", + "FEEDBACK_BACK": "Zpět", + "FEEDBACK_CONTRIBUTE": "Přispět do projektu", + "FEEDBACK_CONTRIBUTE_DESC": "Kód, design, překlady a další", + "FEEDBACK_PRIVATE": "Napsat e-mail správci", + "FEEDBACK_PRIVATE_DESC": "Poslat soukromou zprávu", + "FEEDBACK_PUBLIC": "Napsat na GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "Ostatní mohou vidět a reagovat", + "FEEDBACK_TITLE": "Jak chcete pomoci?", + "TITLE": "Líbí se vám Super Productivity?", + "TXT": "Je to bezplatný projekt s otevřeným zdrojovým kódem, který vytvářejí nadšenci – žádné sledování, žádné reklamy. Hodnocení nebo krátká zpráva pomáhá, aby si jej našlo více lidí." }, "FINISH_DAY_BEFORE_EXIT": { "C": { diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index edc8137184..e73ba17bcc 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -181,10 +181,22 @@ } }, "D_RATE": { - "A_HOW": "Wie und wo zu bewerten", - "BTN_DONT_BOTHER": "Belästige mich nicht wieder", - "TITLE": "🙈 Verzeihung, aber...", - "TXT": "Sie würden dem Projekt immens helfen, wenn Sie es gut bewerten, falls Sie es mögen!" + "A_HOW": "Wie bewerten", + "BTN_DONT_BOTHER": "Nicht mehr fragen", + "BTN_FEEDBACK": "Feedback geben", + "BTN_LATER": "Vielleicht später", + "BTN_RATE_APP_STORE": "Im App Store bewerten", + "BTN_RATE_PLAY_STORE": "Im Play Store bewerten", + "FEEDBACK_BACK": "Zurück", + "FEEDBACK_CONTRIBUTE": "Zum Projekt beitragen", + "FEEDBACK_CONTRIBUTE_DESC": "Code, Design, Übersetzungen und mehr", + "FEEDBACK_PRIVATE": "Maintainer anschreiben", + "FEEDBACK_PRIVATE_DESC": "Eine private Nachricht senden", + "FEEDBACK_PUBLIC": "In GitHub Discussions posten", + "FEEDBACK_PUBLIC_DESC": "Andere können sehen und antworten", + "FEEDBACK_TITLE": "Wie möchten Sie helfen?", + "TITLE": "Gefällt Ihnen Super Productivity?", + "TXT": "Es ist ein kostenloses Open-Source-Projekt, gebaut von Enthusiasten – kein Tracking, keine Werbung. Eine Bewertung oder kurze Nachricht hilft, dass es mehr Leute finden." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index c4d017fac6..0485f4a9ff 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -218,10 +218,22 @@ } }, "D_RATE": { - "A_HOW": "How and where to rate", - "BTN_DONT_BOTHER": "Don't bother me again", - "TITLE": "🙈 Please forgive us, but...", - "TXT": "You will help the project immensely by giving it a good rating, if you like it!" + "A_HOW": "How to rate", + "BTN_DONT_BOTHER": "Don't ask again", + "BTN_FEEDBACK": "Give feedback", + "BTN_LATER": "Maybe later", + "BTN_RATE_APP_STORE": "Rate on App Store", + "BTN_RATE_PLAY_STORE": "Rate on Play Store", + "FEEDBACK_BACK": "Back", + "FEEDBACK_CONTRIBUTE": "Contribute to the project", + "FEEDBACK_CONTRIBUTE_DESC": "Code, design, translations, and more", + "FEEDBACK_PRIVATE": "Email maintainer", + "FEEDBACK_PRIVATE_DESC": "Send a private message", + "FEEDBACK_PUBLIC": "Post on GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "Others can see and respond", + "FEEDBACK_TITLE": "How would you like to help?", + "TITLE": "Enjoying Super Productivity?", + "TXT": "It's a free, open-source project built by enthusiasts – no tracking, no ads. A rating or short message helps more people find it." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/es.json b/src/assets/i18n/es.json index 93f2ec394c..96dcc9f3ed 100644 --- a/src/assets/i18n/es.json +++ b/src/assets/i18n/es.json @@ -181,10 +181,22 @@ } }, "D_RATE": { - "A_HOW": "Cómo y dónde calificar", - "BTN_DONT_BOTHER": "No me molestes de nuevo", - "TITLE": "🙈 Por favor, perdónanos, pero...", - "TXT": "¡Ayudarías inmensamente al proyecto al darle una buena calificación, si te gusta!" + "A_HOW": "Cómo calificar", + "BTN_DONT_BOTHER": "No volver a preguntar", + "BTN_FEEDBACK": "Enviar comentarios", + "BTN_LATER": "Quizás más tarde", + "BTN_RATE_APP_STORE": "Calificar en App Store", + "BTN_RATE_PLAY_STORE": "Calificar en Play Store", + "FEEDBACK_BACK": "Volver", + "FEEDBACK_CONTRIBUTE": "Contribuir al proyecto", + "FEEDBACK_CONTRIBUTE_DESC": "Código, diseño, traducciones y más", + "FEEDBACK_PRIVATE": "Escribir al mantenedor", + "FEEDBACK_PRIVATE_DESC": "Enviar un mensaje privado", + "FEEDBACK_PUBLIC": "Publicar en GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "Otros pueden verlo y responder", + "FEEDBACK_TITLE": "¿Cómo te gustaría ayudar?", + "TITLE": "¿Te gusta Super Productivity?", + "TXT": "Es un proyecto gratuito y de código abierto hecho por entusiastas — sin rastreo ni anuncios. Una calificación o un mensaje breve ayuda a que más personas lo descubran." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/fa.json b/src/assets/i18n/fa.json index 853f4e2c89..25186e0936 100644 --- a/src/assets/i18n/fa.json +++ b/src/assets/i18n/fa.json @@ -171,10 +171,22 @@ } }, "D_RATE": { - "A_HOW": "چگونه و کجا امتیاز دهیم", - "BTN_DONT_BOTHER": "دوباره مزاحم من نکن", - "TITLE": "🙈 لطفا ما را ببخشید، اما...", - "TXT": "اگر دوست دارید، با دادن امتیاز خوب، به پروژه کمک زیادی خواهید کرد!" + "A_HOW": "چگونه امتیاز دهیم", + "BTN_DONT_BOTHER": "دیگر نپرس", + "BTN_FEEDBACK": "ارسال بازخورد", + "BTN_LATER": "شاید بعداً", + "BTN_RATE_APP_STORE": "در App Store امتیاز دهید", + "BTN_RATE_PLAY_STORE": "در Play Store امتیاز دهید", + "FEEDBACK_BACK": "بازگشت", + "FEEDBACK_CONTRIBUTE": "مشارکت در پروژه", + "FEEDBACK_CONTRIBUTE_DESC": "کد، طراحی، ترجمه و موارد دیگر", + "FEEDBACK_PRIVATE": "ایمیل به نگهدارنده", + "FEEDBACK_PRIVATE_DESC": "ارسال پیام خصوصی", + "FEEDBACK_PUBLIC": "ارسال در GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "دیگران می‌بینند و پاسخ می‌دهند", + "FEEDBACK_TITLE": "چگونه دوست دارید کمک کنید؟", + "TITLE": "از Super Productivity لذت می‌برید؟", + "TXT": "این یک پروژه رایگان و متن‌باز ساخته‌شده توسط علاقه‌مندان است — بدون ردیابی، بدون تبلیغات. یک امتیاز یا پیام کوتاه کمک می‌کند افراد بیشتری آن را پیدا کنند." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/fi.json b/src/assets/i18n/fi.json index bcde72a4da..00018b1253 100644 --- a/src/assets/i18n/fi.json +++ b/src/assets/i18n/fi.json @@ -176,10 +176,22 @@ } }, "D_RATE": { - "A_HOW": "Miten ja missä arvostella", - "BTN_DONT_BOTHER": "Älä häiritse minua uudelleen", - "TITLE": "🙈 Pyydämme anteeksi, mutta...", - "TXT": "Auttaisit projektia valtavasti antamalla sille hyvän arvion, jos pidät siitä!" + "A_HOW": "Miten arvostella", + "BTN_DONT_BOTHER": "Älä kysy uudelleen", + "BTN_FEEDBACK": "Anna palautetta", + "BTN_LATER": "Ehkä myöhemmin", + "BTN_RATE_APP_STORE": "Arvostele App Storessa", + "BTN_RATE_PLAY_STORE": "Arvostele Play Storessa", + "FEEDBACK_BACK": "Takaisin", + "FEEDBACK_CONTRIBUTE": "Osallistu projektiin", + "FEEDBACK_CONTRIBUTE_DESC": "Koodi, suunnittelu, käännökset ja muuta", + "FEEDBACK_PRIVATE": "Lähetä sähköpostia ylläpitäjälle", + "FEEDBACK_PRIVATE_DESC": "Lähetä yksityinen viesti", + "FEEDBACK_PUBLIC": "Kirjoita GitHub Discussionsiin", + "FEEDBACK_PUBLIC_DESC": "Muut näkevät ja voivat vastata", + "FEEDBACK_TITLE": "Miten haluaisit auttaa?", + "TITLE": "Pidätkö Super Productivitysta?", + "TXT": "Se on ilmainen avoimen lähdekoodin projekti, jonka tekevät innokkaat harrastajat – ei seurantaa eikä mainoksia. Arvostelu tai lyhyt viesti auttaa useampia löytämään sen." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json index 2c93b23c6d..12fc609a79 100644 --- a/src/assets/i18n/fr.json +++ b/src/assets/i18n/fr.json @@ -176,10 +176,22 @@ } }, "D_RATE": { - "A_HOW": "Comment et où évaluer", - "BTN_DONT_BOTHER": "Ne me dérange plus", - "TITLE": "\u001f926\u001f3fd Veuillez nous pardonner, mais...", - "TXT": "Vous aideriez énormément le projet en l'évaluant positivement, si vous l'aimez !" + "A_HOW": "Comment évaluer", + "BTN_DONT_BOTHER": "Ne plus me demander", + "BTN_FEEDBACK": "Envoyer un retour", + "BTN_LATER": "Peut-être plus tard", + "BTN_RATE_APP_STORE": "Noter sur l'App Store", + "BTN_RATE_PLAY_STORE": "Noter sur le Play Store", + "FEEDBACK_BACK": "Retour", + "FEEDBACK_CONTRIBUTE": "Contribuer au projet", + "FEEDBACK_CONTRIBUTE_DESC": "Code, design, traductions et plus", + "FEEDBACK_PRIVATE": "Écrire au mainteneur", + "FEEDBACK_PRIVATE_DESC": "Envoyer un message privé", + "FEEDBACK_PUBLIC": "Publier sur GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "Visible et ouvert aux réponses", + "FEEDBACK_TITLE": "Comment souhaitez-vous aider ?", + "TITLE": "Vous appréciez Super Productivity ?", + "TXT": "C'est un projet gratuit et open source conçu par des passionnés — sans pistage ni publicité. Une note ou un court message aide d'autres personnes à le découvrir." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/hr.json b/src/assets/i18n/hr.json index be63ac1105..a634540af6 100644 --- a/src/assets/i18n/hr.json +++ b/src/assets/i18n/hr.json @@ -207,10 +207,22 @@ } }, "D_RATE": { - "A_HOW": "Kako i gdje ocijeniti", - "BTN_DONT_BOTHER": "Nemoj me više gnjaviti", - "TITLE": "🙈 Oprosti, ali …", - "TXT": "Puno bi pomogao/la projektu ako ga dobro ocijeniš, ako ti se sviđa!" + "A_HOW": "Kako ocijeniti", + "BTN_DONT_BOTHER": "Ne pitaj ponovno", + "BTN_FEEDBACK": "Pošalji povratnu informaciju", + "BTN_LATER": "Možda kasnije", + "BTN_RATE_APP_STORE": "Ocijeni na App Storeu", + "BTN_RATE_PLAY_STORE": "Ocijeni na Play Storeu", + "FEEDBACK_BACK": "Natrag", + "FEEDBACK_CONTRIBUTE": "Doprinesi projektu", + "FEEDBACK_CONTRIBUTE_DESC": "Kod, dizajn, prijevodi i više", + "FEEDBACK_PRIVATE": "Pošalji e-mail održavatelju", + "FEEDBACK_PRIVATE_DESC": "Pošalji privatnu poruku", + "FEEDBACK_PUBLIC": "Objavi na GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "Drugi mogu vidjeti i odgovoriti", + "FEEDBACK_TITLE": "Kako želiš pomoći?", + "TITLE": "Sviđa ti se Super Productivity?", + "TXT": "To je besplatan projekt otvorenog koda koji rade entuzijasti — bez praćenja, bez oglasa. Ocjena ili kratka poruka pomaže da ga otkrije više ljudi." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/id.json b/src/assets/i18n/id.json index 935904c8ef..575a4b28f9 100644 --- a/src/assets/i18n/id.json +++ b/src/assets/i18n/id.json @@ -176,10 +176,22 @@ } }, "D_RATE": { - "A_HOW": "Bagaimana dan di mana menilai", - "BTN_DONT_BOTHER": "Jangan ganggu aku lagi", - "TITLE": "🙈 Maafkan kami, tapi...", - "TXT": "Anda akan sangat membantu proyek dengan memberikannya peringkat yang bagus, jika Anda menyukainya!" + "A_HOW": "Cara menilai", + "BTN_DONT_BOTHER": "Jangan tanya lagi", + "BTN_FEEDBACK": "Beri masukan", + "BTN_LATER": "Mungkin nanti", + "BTN_RATE_APP_STORE": "Nilai di App Store", + "BTN_RATE_PLAY_STORE": "Nilai di Play Store", + "FEEDBACK_BACK": "Kembali", + "FEEDBACK_CONTRIBUTE": "Berkontribusi ke proyek", + "FEEDBACK_CONTRIBUTE_DESC": "Kode, desain, terjemahan, dan lainnya", + "FEEDBACK_PRIVATE": "Email ke pengelola", + "FEEDBACK_PRIVATE_DESC": "Kirim pesan pribadi", + "FEEDBACK_PUBLIC": "Posting di GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "Orang lain bisa melihat dan menanggapi", + "FEEDBACK_TITLE": "Bagaimana Anda ingin membantu?", + "TITLE": "Suka Super Productivity?", + "TXT": "Ini adalah proyek gratis dan sumber terbuka yang dibuat oleh para penggemar — tanpa pelacakan, tanpa iklan. Penilaian atau pesan singkat membantu lebih banyak orang menemukannya." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/it.json b/src/assets/i18n/it.json index 10e72824fe..193c29ce6d 100644 --- a/src/assets/i18n/it.json +++ b/src/assets/i18n/it.json @@ -176,10 +176,22 @@ } }, "D_RATE": { - "A_HOW": "Come e dove lasciare una recensione", - "BTN_DONT_BOTHER": "Non chiederlo di nuovo", - "TITLE": "🙈 Perdonaci, ma...", - "TXT": "Aiuteresti il progetto immensamente lasciando una buona recensione, se ti piace!" + "A_HOW": "Come valutare", + "BTN_DONT_BOTHER": "Non chiedere più", + "BTN_FEEDBACK": "Lascia un feedback", + "BTN_LATER": "Forse più tardi", + "BTN_RATE_APP_STORE": "Valuta su App Store", + "BTN_RATE_PLAY_STORE": "Valuta su Play Store", + "FEEDBACK_BACK": "Indietro", + "FEEDBACK_CONTRIBUTE": "Contribuisci al progetto", + "FEEDBACK_CONTRIBUTE_DESC": "Codice, design, traduzioni e altro", + "FEEDBACK_PRIVATE": "Scrivi al manutentore", + "FEEDBACK_PRIVATE_DESC": "Invia un messaggio privato", + "FEEDBACK_PUBLIC": "Pubblica su GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "Altri possono vedere e rispondere", + "FEEDBACK_TITLE": "Come vuoi aiutare?", + "TITLE": "Ti piace Super Productivity?", + "TXT": "È un progetto gratuito e open source creato da appassionati — niente tracciamento, niente pubblicità. Una recensione o un breve messaggio aiuta più persone a scoprirlo." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/ja.json b/src/assets/i18n/ja.json index b1fb3d3c3b..ba116415ae 100644 --- a/src/assets/i18n/ja.json +++ b/src/assets/i18n/ja.json @@ -171,10 +171,22 @@ } }, "D_RATE": { - "A_HOW": "評価方法と場所", - "BTN_DONT_BOTHER": "二度と気にしないで", - "TITLE": "🙈 ご容赦ください、しかし...", - "TXT": "あなたがそれを好きなら、あなたはそれに良い評価を与えることによって、プロジェクトを大いに助けるでしょう、 !" + "A_HOW": "評価の方法", + "BTN_DONT_BOTHER": "今後表示しない", + "BTN_FEEDBACK": "フィードバックを送る", + "BTN_LATER": "あとで", + "BTN_RATE_APP_STORE": "App Store で評価", + "BTN_RATE_PLAY_STORE": "Play Store で評価", + "FEEDBACK_BACK": "戻る", + "FEEDBACK_CONTRIBUTE": "プロジェクトに貢献する", + "FEEDBACK_CONTRIBUTE_DESC": "コード、デザイン、翻訳など", + "FEEDBACK_PRIVATE": "メンテナーにメール", + "FEEDBACK_PRIVATE_DESC": "非公開のメッセージを送る", + "FEEDBACK_PUBLIC": "GitHub Discussions に投稿", + "FEEDBACK_PUBLIC_DESC": "他の人が見て返信できます", + "FEEDBACK_TITLE": "どのように協力しますか?", + "TITLE": "Super Productivity は気に入りましたか?", + "TXT": "これは有志による無料のオープンソースプロジェクトです — トラッキングも広告もありません。評価や短いメッセージが、より多くの人に届けるのに役立ちます。" }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/ko.json b/src/assets/i18n/ko.json index fd9dc464f7..53e913ea9c 100644 --- a/src/assets/i18n/ko.json +++ b/src/assets/i18n/ko.json @@ -160,10 +160,22 @@ } }, "D_RATE": { - "A_HOW": "평가 방법 및 위치", - "BTN_DONT_BOTHER": "다시는 나를 괴롭히지 마라", - "TITLE": "🙈 부디 용서해 주세요만...", - "TXT": "당신이 그것을 좋아한다면 좋은 평가를 주면 프로젝트에 엄청난 도움이 될 것입니다!" + "A_HOW": "평가하는 방법", + "BTN_DONT_BOTHER": "다시 묻지 않기", + "BTN_FEEDBACK": "피드백 보내기", + "BTN_LATER": "나중에", + "BTN_RATE_APP_STORE": "App Store에서 평가", + "BTN_RATE_PLAY_STORE": "Play Store에서 평가", + "FEEDBACK_BACK": "뒤로", + "FEEDBACK_CONTRIBUTE": "프로젝트에 기여하기", + "FEEDBACK_CONTRIBUTE_DESC": "코드, 디자인, 번역 등", + "FEEDBACK_PRIVATE": "관리자에게 이메일", + "FEEDBACK_PRIVATE_DESC": "비공개 메시지 보내기", + "FEEDBACK_PUBLIC": "GitHub Discussions에 게시", + "FEEDBACK_PUBLIC_DESC": "다른 사람이 보고 답글 가능", + "FEEDBACK_TITLE": "어떻게 도와주시겠어요?", + "TITLE": "Super Productivity가 마음에 드시나요?", + "TXT": "무료 오픈소스 프로젝트로 애호가들이 만들었습니다 — 추적도 광고도 없습니다. 평가나 짧은 메시지가 더 많은 사람들이 이 앱을 발견하는 데 도움이 됩니다." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/nb.json b/src/assets/i18n/nb.json index 8b6c19ac48..2ad30cc05c 100644 --- a/src/assets/i18n/nb.json +++ b/src/assets/i18n/nb.json @@ -176,10 +176,22 @@ } }, "D_RATE": { - "A_HOW": "Hvordan og hvor du skal rangere", - "BTN_DONT_BOTHER": "Ikke plag meg igjen", - "TITLE": "🙈 Vennligst tilgi oss, men...", - "TXT": "Du vil hjelpe prosjektet enormt ved å gi det en god vurdering, hvis du liker det!" + "A_HOW": "Hvordan vurdere", + "BTN_DONT_BOTHER": "Ikke spør igjen", + "BTN_FEEDBACK": "Gi tilbakemelding", + "BTN_LATER": "Kanskje senere", + "BTN_RATE_APP_STORE": "Vurder i App Store", + "BTN_RATE_PLAY_STORE": "Vurder i Play Store", + "FEEDBACK_BACK": "Tilbake", + "FEEDBACK_CONTRIBUTE": "Bidra til prosjektet", + "FEEDBACK_CONTRIBUTE_DESC": "Kode, design, oversettelser og mer", + "FEEDBACK_PRIVATE": "Send e-post til vedlikeholder", + "FEEDBACK_PRIVATE_DESC": "Send en privat melding", + "FEEDBACK_PUBLIC": "Skriv på GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "Andre kan se og svare", + "FEEDBACK_TITLE": "Hvordan vil du hjelpe?", + "TITLE": "Liker du Super Productivity?", + "TXT": "Det er et gratis prosjekt med åpen kildekode laget av entusiaster – ingen sporing, ingen reklame. En vurdering eller kort melding hjelper flere å finne det." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/nl.json b/src/assets/i18n/nl.json index a294115707..f554db010e 100644 --- a/src/assets/i18n/nl.json +++ b/src/assets/i18n/nl.json @@ -176,10 +176,22 @@ } }, "D_RATE": { - "A_HOW": "Hoe en waar te beoordelen", - "BTN_DONT_BOTHER": "Val me niet meer lastig", - "TITLE": "🙈 Vergeef ons alstublieft, maar...", - "TXT": "Je zou het project enorm helpen door het een goede beoordeling te geven, als je het leuk vindt!" + "A_HOW": "Hoe te beoordelen", + "BTN_DONT_BOTHER": "Niet meer vragen", + "BTN_FEEDBACK": "Feedback geven", + "BTN_LATER": "Misschien later", + "BTN_RATE_APP_STORE": "Beoordeel in App Store", + "BTN_RATE_PLAY_STORE": "Beoordeel in Play Store", + "FEEDBACK_BACK": "Terug", + "FEEDBACK_CONTRIBUTE": "Bijdragen aan het project", + "FEEDBACK_CONTRIBUTE_DESC": "Code, design, vertalingen en meer", + "FEEDBACK_PRIVATE": "E-mail de maintainer", + "FEEDBACK_PRIVATE_DESC": "Stuur een privébericht", + "FEEDBACK_PUBLIC": "Plaats op GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "Anderen kunnen meelezen en reageren", + "FEEDBACK_TITLE": "Hoe wil je helpen?", + "TITLE": "Gebruik je Super Productivity graag?", + "TXT": "Het is een gratis open-sourceproject gemaakt door enthousiastelingen — geen tracking, geen advertenties. Een beoordeling of korte boodschap helpt meer mensen het te vinden." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/pl.json b/src/assets/i18n/pl.json index c45aadb033..85d352288c 100644 --- a/src/assets/i18n/pl.json +++ b/src/assets/i18n/pl.json @@ -192,10 +192,22 @@ } }, "D_RATE": { - "A_HOW": "Jak i gdzie oceniać", - "BTN_DONT_BOTHER": "Nie zawracaj mi więcej głowy", - "TITLE": "🙈 Proszę nam wybaczyć, ale...", - "TXT": "Bardzo pomógłbyś projektowi, wystawiając mu dobrą ocenę, jeśli Ci się spodoba!" + "A_HOW": "Jak oceniać", + "BTN_DONT_BOTHER": "Nie pytaj ponownie", + "BTN_FEEDBACK": "Wyślij opinię", + "BTN_LATER": "Może później", + "BTN_RATE_APP_STORE": "Oceń w App Store", + "BTN_RATE_PLAY_STORE": "Oceń w Play Store", + "FEEDBACK_BACK": "Wstecz", + "FEEDBACK_CONTRIBUTE": "Przyczynij się do projektu", + "FEEDBACK_CONTRIBUTE_DESC": "Kod, design, tłumaczenia i więcej", + "FEEDBACK_PRIVATE": "Napisz do opiekuna", + "FEEDBACK_PRIVATE_DESC": "Wyślij prywatną wiadomość", + "FEEDBACK_PUBLIC": "Opublikuj w GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "Inni mogą zobaczyć i odpowiedzieć", + "FEEDBACK_TITLE": "Jak chcesz pomóc?", + "TITLE": "Podoba Ci się Super Productivity?", + "TXT": "To darmowy projekt open source tworzony przez pasjonatów — bez śledzenia, bez reklam. Ocena lub krótka wiadomość pomaga większej liczbie osób go znaleźć." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/pt-br.json b/src/assets/i18n/pt-br.json index af21dae6b9..7961ea1e39 100644 --- a/src/assets/i18n/pt-br.json +++ b/src/assets/i18n/pt-br.json @@ -208,10 +208,22 @@ } }, "D_RATE": { - "A_HOW": "Como e onde avaliar", - "BTN_DONT_BOTHER": "Não me incomode novamente", - "TITLE": "🙈 Por favor, nos perdoe, mas...", - "TXT": "Você ajudará o projeto imensamente dando uma boa avaliação, se gostar dele!" + "A_HOW": "Como avaliar", + "BTN_DONT_BOTHER": "Não perguntar de novo", + "BTN_FEEDBACK": "Enviar feedback", + "BTN_LATER": "Talvez mais tarde", + "BTN_RATE_APP_STORE": "Avaliar na App Store", + "BTN_RATE_PLAY_STORE": "Avaliar na Play Store", + "FEEDBACK_BACK": "Voltar", + "FEEDBACK_CONTRIBUTE": "Contribuir com o projeto", + "FEEDBACK_CONTRIBUTE_DESC": "Código, design, traduções e mais", + "FEEDBACK_PRIVATE": "Enviar e-mail ao mantenedor", + "FEEDBACK_PRIVATE_DESC": "Enviar uma mensagem privada", + "FEEDBACK_PUBLIC": "Postar no GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "Outros podem ver e responder", + "FEEDBACK_TITLE": "Como você gostaria de ajudar?", + "TITLE": "Gostando do Super Productivity?", + "TXT": "É um projeto gratuito e de código aberto feito por entusiastas — sem rastreamento, sem anúncios. Uma avaliação ou uma mensagem curta ajuda mais pessoas a descobri-lo." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/pt.json b/src/assets/i18n/pt.json index 6f4c156dc4..614acffd34 100644 --- a/src/assets/i18n/pt.json +++ b/src/assets/i18n/pt.json @@ -176,10 +176,22 @@ } }, "D_RATE": { - "A_HOW": "Como e onde avaliar", - "BTN_DONT_BOTHER": "Não me incomode novamente", - "TITLE": "🙈 Por favor, perdoe-nos, mas...", - "TXT": "Você ajudaria imensamente o projeto dando uma boa classificação, se gostar!" + "A_HOW": "Como avaliar", + "BTN_DONT_BOTHER": "Não perguntar novamente", + "BTN_FEEDBACK": "Enviar comentários", + "BTN_LATER": "Talvez mais tarde", + "BTN_RATE_APP_STORE": "Avaliar na App Store", + "BTN_RATE_PLAY_STORE": "Avaliar na Play Store", + "FEEDBACK_BACK": "Voltar", + "FEEDBACK_CONTRIBUTE": "Contribuir para o projeto", + "FEEDBACK_CONTRIBUTE_DESC": "Código, design, traduções e mais", + "FEEDBACK_PRIVATE": "Enviar e-mail ao responsável", + "FEEDBACK_PRIVATE_DESC": "Enviar uma mensagem privada", + "FEEDBACK_PUBLIC": "Publicar no GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "Outros podem ver e responder", + "FEEDBACK_TITLE": "Como gostaria de ajudar?", + "TITLE": "Está a gostar do Super Productivity?", + "TXT": "É um projeto gratuito e de código aberto feito por entusiastas — sem rastreio, sem anúncios. Uma avaliação ou uma mensagem curta ajuda mais pessoas a descobri-lo." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/ro-md.json b/src/assets/i18n/ro-md.json index 5b94dd3757..b40c1d132f 100644 --- a/src/assets/i18n/ro-md.json +++ b/src/assets/i18n/ro-md.json @@ -192,10 +192,22 @@ } }, "D_RATE": { - "A_HOW": "Cum și unde să acorzi o notă", - "BTN_DONT_BOTHER": "Nu mă mai deranja din nou", - "TITLE": "🙈 Te rog iartă-ne, dar...", - "TXT": "Vei ajuta proiectul enorm de mult dacă îi acorzi o notă bună, dacă îți place!" + "A_HOW": "Cum acorzi o notă", + "BTN_DONT_BOTHER": "Nu mă mai întreba", + "BTN_FEEDBACK": "Trimite feedback", + "BTN_LATER": "Poate mai tîrziu", + "BTN_RATE_APP_STORE": "Acordă o notă pe App Store", + "BTN_RATE_PLAY_STORE": "Acordă o notă pe Play Store", + "FEEDBACK_BACK": "Înapoi", + "FEEDBACK_CONTRIBUTE": "Contribuie la proiect", + "FEEDBACK_CONTRIBUTE_DESC": "Cod, design, traduceri și altele", + "FEEDBACK_PRIVATE": "Scrie-i întreținătorului pe e-mail", + "FEEDBACK_PRIVATE_DESC": "Trimite un mesaj privat", + "FEEDBACK_PUBLIC": "Postează pe GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "Alții pot vedea și răspunde", + "FEEDBACK_TITLE": "Cum vrei să ajuți?", + "TITLE": "Îți place Super Productivity?", + "TXT": "Este un proiect gratuit și open-source realizat de pasionați — fără urmărire, fără reclame. O notă sau un mesaj scurt ajută mai mulți oameni să-l descopere." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/ro.json b/src/assets/i18n/ro.json index ec9ae88b7f..1f1e42a1fa 100644 --- a/src/assets/i18n/ro.json +++ b/src/assets/i18n/ro.json @@ -192,10 +192,22 @@ } }, "D_RATE": { - "A_HOW": "Cum și unde să acorzi o notă", - "BTN_DONT_BOTHER": "Nu mă mai deranja din nou", - "TITLE": "🙈 Te rog iartă-ne, dar...", - "TXT": "Vei ajuta proiectul enorm de mult dacă îi acorzi o notă bună, dacă îți place!" + "A_HOW": "Cum acorzi o notă", + "BTN_DONT_BOTHER": "Nu mă mai întreba", + "BTN_FEEDBACK": "Trimite feedback", + "BTN_LATER": "Poate mai târziu", + "BTN_RATE_APP_STORE": "Acordă o notă pe App Store", + "BTN_RATE_PLAY_STORE": "Acordă o notă pe Play Store", + "FEEDBACK_BACK": "Înapoi", + "FEEDBACK_CONTRIBUTE": "Contribuie la proiect", + "FEEDBACK_CONTRIBUTE_DESC": "Cod, design, traduceri și altele", + "FEEDBACK_PRIVATE": "Scrie-i întreținătorului pe e-mail", + "FEEDBACK_PRIVATE_DESC": "Trimite un mesaj privat", + "FEEDBACK_PUBLIC": "Postează pe GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "Alții pot vedea și răspunde", + "FEEDBACK_TITLE": "Cum vrei să ajuți?", + "TITLE": "Îți place Super Productivity?", + "TXT": "Este un proiect gratuit și open-source realizat de pasionați — fără urmărire, fără reclame. O notă sau un mesaj scurt ajută mai mulți oameni să-l descopere." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/ru.json b/src/assets/i18n/ru.json index ef2cef52b1..ae8dca3b09 100644 --- a/src/assets/i18n/ru.json +++ b/src/assets/i18n/ru.json @@ -176,10 +176,22 @@ } }, "D_RATE": { - "A_HOW": "Как и где выставлять оценки", - "BTN_DONT_BOTHER": "Больше не беспокойте меня", - "TITLE": "🙈 Пожалуйста, простите нас, но...", - "TXT": "Вы бы очень помогли проекту, если бы дали ему хорошую оценку, если он вам нравится!" + "A_HOW": "Как оценить", + "BTN_DONT_BOTHER": "Больше не спрашивать", + "BTN_FEEDBACK": "Отправить отзыв", + "BTN_LATER": "Может, позже", + "BTN_RATE_APP_STORE": "Оценить в App Store", + "BTN_RATE_PLAY_STORE": "Оценить в Play Store", + "FEEDBACK_BACK": "Назад", + "FEEDBACK_CONTRIBUTE": "Внести вклад в проект", + "FEEDBACK_CONTRIBUTE_DESC": "Код, дизайн, переводы и другое", + "FEEDBACK_PRIVATE": "Написать сопровождающему", + "FEEDBACK_PRIVATE_DESC": "Отправить личное сообщение", + "FEEDBACK_PUBLIC": "Написать в GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "Другие увидят и смогут ответить", + "FEEDBACK_TITLE": "Как вы хотели бы помочь?", + "TITLE": "Нравится ли вам Super Productivity?", + "TXT": "Это бесплатный проект с открытым исходным кодом, созданный энтузиастами — без отслеживания и рекламы. Оценка или короткое сообщение помогает большему числу людей найти приложение." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/sk.json b/src/assets/i18n/sk.json index fab21ae88e..a828df3b5e 100644 --- a/src/assets/i18n/sk.json +++ b/src/assets/i18n/sk.json @@ -176,10 +176,22 @@ } }, "D_RATE": { - "A_HOW": "Ako a kde hodnotiť", - "BTN_DONT_BOTHER": "Už ma neobťažuj", - "TITLE": "🙈 Prosím, odpusťte nám, ale...", - "TXT": "Projektu by ste nesmierne pomohli, keby ste mu dali dobré hodnotenie, ak sa vám páči!" + "A_HOW": "Ako hodnotiť", + "BTN_DONT_BOTHER": "Už sa nepýtať", + "BTN_FEEDBACK": "Poslať spätnú väzbu", + "BTN_LATER": "Možno neskôr", + "BTN_RATE_APP_STORE": "Ohodnotiť v App Store", + "BTN_RATE_PLAY_STORE": "Ohodnotiť v Play Store", + "FEEDBACK_BACK": "Späť", + "FEEDBACK_CONTRIBUTE": "Prispieť do projektu", + "FEEDBACK_CONTRIBUTE_DESC": "Kód, dizajn, preklady a viac", + "FEEDBACK_PRIVATE": "Napísať e-mail správcovi", + "FEEDBACK_PRIVATE_DESC": "Poslať súkromnú správu", + "FEEDBACK_PUBLIC": "Napísať na GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "Ostatní vidia a môžu reagovať", + "FEEDBACK_TITLE": "Ako chcete pomôcť?", + "TITLE": "Páči sa vám Super Productivity?", + "TXT": "Je to bezplatný projekt s otvoreným zdrojovým kódom vytváraný nadšencami – žiadne sledovanie, žiadne reklamy. Hodnotenie alebo krátka správa pomáha, aby ho našlo viac ľudí." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/sv.json b/src/assets/i18n/sv.json index 8759f3cd08..f61a7e5d09 100644 --- a/src/assets/i18n/sv.json +++ b/src/assets/i18n/sv.json @@ -171,10 +171,22 @@ } }, "D_RATE": { - "A_HOW": "Hur och var man ska betygsätta", - "BTN_DONT_BOTHER": "Stör mig inte igen.", - "TITLE": "🙈 Förlåt oss, men...", - "TXT": "Du skulle hjälpa projektet enormt genom att ge det ett bra betyg, om du gillar det!" + "A_HOW": "Så betygsätter du", + "BTN_DONT_BOTHER": "Fråga inte igen", + "BTN_FEEDBACK": "Lämna feedback", + "BTN_LATER": "Kanske senare", + "BTN_RATE_APP_STORE": "Betygsätt i App Store", + "BTN_RATE_PLAY_STORE": "Betygsätt i Play Store", + "FEEDBACK_BACK": "Tillbaka", + "FEEDBACK_CONTRIBUTE": "Bidra till projektet", + "FEEDBACK_CONTRIBUTE_DESC": "Kod, design, översättningar och mer", + "FEEDBACK_PRIVATE": "Mejla underhållaren", + "FEEDBACK_PRIVATE_DESC": "Skicka ett privat meddelande", + "FEEDBACK_PUBLIC": "Skriv på GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "Andra kan se och svara", + "FEEDBACK_TITLE": "Hur vill du hjälpa till?", + "TITLE": "Gillar du Super Productivity?", + "TXT": "Det är ett gratis projekt med öppen källkod byggt av entusiaster – ingen spårning, inga annonser. Ett betyg eller ett kort meddelande hjälper fler att upptäcka det." }, "VOICE_REMINDER": { "FORM": { diff --git a/src/assets/i18n/tr.json b/src/assets/i18n/tr.json index 94327ec881..b6a8221d4c 100644 --- a/src/assets/i18n/tr.json +++ b/src/assets/i18n/tr.json @@ -208,10 +208,22 @@ } }, "D_RATE": { - "A_HOW": "Nasıl ve nerede değerlendirilir", - "BTN_DONT_BOTHER": "Beni bir daha rahatsız etme", - "TITLE": "🙈 Lütfen bizi affedin ama...", - "TXT": "Beğenirseniz, iyi bir puan vererek projeye son derece yardımcı olursunuz!" + "A_HOW": "Nasıl değerlendirilir", + "BTN_DONT_BOTHER": "Bir daha sorma", + "BTN_FEEDBACK": "Geri bildirim gönder", + "BTN_LATER": "Belki daha sonra", + "BTN_RATE_APP_STORE": "App Store'da değerlendir", + "BTN_RATE_PLAY_STORE": "Play Store'da değerlendir", + "FEEDBACK_BACK": "Geri", + "FEEDBACK_CONTRIBUTE": "Projeye katkıda bulun", + "FEEDBACK_CONTRIBUTE_DESC": "Kod, tasarım, çeviri ve daha fazlası", + "FEEDBACK_PRIVATE": "Geliştiriciye e-posta gönder", + "FEEDBACK_PRIVATE_DESC": "Özel bir mesaj gönder", + "FEEDBACK_PUBLIC": "GitHub Discussions'a yaz", + "FEEDBACK_PUBLIC_DESC": "Başkaları görebilir ve yanıtlayabilir", + "FEEDBACK_TITLE": "Nasıl yardım etmek istersin?", + "TITLE": "Super Productivity'yi beğeniyor musun?", + "TXT": "Bu, meraklılar tarafından yapılmış ücretsiz ve açık kaynaklı bir projedir — takip yok, reklam yok. Bir puan veya kısa bir mesaj, daha fazla kişinin uygulamayı bulmasına yardımcı olur." }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/uk.json b/src/assets/i18n/uk.json index ae47c2f54e..179989de1b 100644 --- a/src/assets/i18n/uk.json +++ b/src/assets/i18n/uk.json @@ -194,10 +194,22 @@ } }, "D_RATE": { - "A_HOW": "Як і де оцінювати", - "BTN_DONT_BOTHER": "Не турбувати більше", - "TITLE": "🙈 Пробачте, будь ласка, але...", - "TXT": "Ви б дуже допомогли проекту, поставивши йому хорошу оцінку, якщо вам це подобається!" + "A_HOW": "Як оцінити", + "BTN_DONT_BOTHER": "Більше не запитувати", + "BTN_FEEDBACK": "Надіслати відгук", + "BTN_LATER": "Можливо, пізніше", + "BTN_RATE_APP_STORE": "Оцінити в App Store", + "BTN_RATE_PLAY_STORE": "Оцінити в Play Store", + "FEEDBACK_BACK": "Назад", + "FEEDBACK_CONTRIBUTE": "Зробити внесок у проєкт", + "FEEDBACK_CONTRIBUTE_DESC": "Код, дизайн, переклади тощо", + "FEEDBACK_PRIVATE": "Написати супровіднику", + "FEEDBACK_PRIVATE_DESC": "Надіслати приватне повідомлення", + "FEEDBACK_PUBLIC": "Написати в GitHub Discussions", + "FEEDBACK_PUBLIC_DESC": "Інші можуть побачити та відповісти", + "FEEDBACK_TITLE": "Як ви хочете допомогти?", + "TITLE": "Подобається Super Productivity?", + "TXT": "Це безкоштовний проєкт з відкритим кодом, створений ентузіастами — без відстеження й реклами. Оцінка або коротке повідомлення допомагає більшій кількості людей знайти його." }, "FINISH_DAY_BEFORE_EXIT": { "C": { diff --git a/src/assets/i18n/zh-tw.json b/src/assets/i18n/zh-tw.json index c272404c6e..62f44f8d5e 100644 --- a/src/assets/i18n/zh-tw.json +++ b/src/assets/i18n/zh-tw.json @@ -181,10 +181,22 @@ } }, "D_RATE": { - "A_HOW": "如何和在哪裡評分", - "BTN_DONT_BOTHER": "不要再打擾我", - "TITLE": "🙈 請原諒我們,但是...", - "TXT": "如果您喜歡它,給予好評將對專案有極大幫助!" + "A_HOW": "如何評分", + "BTN_DONT_BOTHER": "不要再詢問", + "BTN_FEEDBACK": "提供意見", + "BTN_LATER": "稍後再說", + "BTN_RATE_APP_STORE": "在 App Store 評分", + "BTN_RATE_PLAY_STORE": "在 Play Store 評分", + "FEEDBACK_BACK": "返回", + "FEEDBACK_CONTRIBUTE": "為此專案貢獻", + "FEEDBACK_CONTRIBUTE_DESC": "程式碼、設計、翻譯等", + "FEEDBACK_PRIVATE": "寄信給維護者", + "FEEDBACK_PRIVATE_DESC": "寄送私人訊息", + "FEEDBACK_PUBLIC": "在 GitHub Discussions 發文", + "FEEDBACK_PUBLIC_DESC": "他人可看到並回覆", + "FEEDBACK_TITLE": "您想如何協助?", + "TITLE": "喜歡 Super Productivity 嗎?", + "TXT": "這是一個由愛好者打造的免費開源專案——沒有追蹤、沒有廣告。一個評分或簡短訊息能幫助更多人發現它。" }, "DROPBOX": { "S": { diff --git a/src/assets/i18n/zh.json b/src/assets/i18n/zh.json index d9df24b135..cb5c0bb3a6 100644 --- a/src/assets/i18n/zh.json +++ b/src/assets/i18n/zh.json @@ -194,10 +194,22 @@ } }, "D_RATE": { - "A_HOW": "如何以及在哪里评分", - "BTN_DONT_BOTHER": "不要再打扰我", - "TITLE": "🙈 请原谅我们,但是...", - "TXT": "如果您喜欢它,给它一个好评,您将极大地帮助这个项目!" + "A_HOW": "如何评分", + "BTN_DONT_BOTHER": "不再询问", + "BTN_FEEDBACK": "提供反馈", + "BTN_LATER": "稍后再说", + "BTN_RATE_APP_STORE": "在 App Store 评分", + "BTN_RATE_PLAY_STORE": "在 Play Store 评分", + "FEEDBACK_BACK": "返回", + "FEEDBACK_CONTRIBUTE": "为项目做贡献", + "FEEDBACK_CONTRIBUTE_DESC": "代码、设计、翻译等", + "FEEDBACK_PRIVATE": "向维护者发邮件", + "FEEDBACK_PRIVATE_DESC": "发送一条私信", + "FEEDBACK_PUBLIC": "在 GitHub Discussions 发帖", + "FEEDBACK_PUBLIC_DESC": "他人可以看到并回复", + "FEEDBACK_TITLE": "您想如何帮助?", + "TITLE": "喜欢 Super Productivity 吗?", + "TXT": "这是一个由爱好者打造的免费开源项目 —— 没有追踪,没有广告。一条评分或简短留言能帮助更多人发现它。" }, "FINISH_DAY_BEFORE_EXIT": { "C": {