feat(rate-dialog): action-aware prompt with feedback split

Replace the apologetic 'Please forgive us' modal with a calm prompt
that routes the primary CTA per platform (Play Store on Android,
App Store on iOS, how-to-rate.md docs on everything else) and offers
a feedback sub-screen with three paths: public (GitHub Discussions),
private (mailto with prefilled version + platform), and contribute
(CONTRIBUTING.md).

Snooze logic: at most two prompts ever (day 32, day 96). Any explicit
Rate / Feedback / Don't-ask-again click triggers permanent opt-out;
ESC and backdrop snooze without penalty. Fixes pre-existing
APP_START_COUNT double-increment on the trigger day.

State persists in localStorage (device-local, not synced). Trigger
logic and platform routing extracted into a pure helper module with
co-located unit tests covering the snooze table and the persistence
layer.

i18n: 12 new keys plus rewritten English for the four legacy keys,
translated into all 26 non-English locales. Body paragraph uses
[innerHTML] so legacy <strong> markup in older locales still renders
correctly until translators update.

Also: docs/how-to-rate.md gets direct App Store / Mac App Store
links for id 1482572463, neutralized 5-star nudging copy, fixed
heading hierarchy, added a GitHub-star entry.
This commit is contained in:
Johannes Millan 2026-05-04 17:27:11 +02:00
parent 84d0f306cb
commit 71b976ce3e
37 changed files with 1021 additions and 181 deletions

View file

@ -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/

View file

@ -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',

View file

@ -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;
});

View file

@ -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<void> {

View file

@ -1,28 +1,106 @@
<h1 mat-dialog-title>{{ T.F.D_RATE.TITLE | translate }}</h1>
@if (view() === 'main') {
<h1 mat-dialog-title>{{ T.F.D_RATE.TITLE | translate }}</h1>
<mat-dialog-content>
<div style="max-width: 400px">
<mat-dialog-content>
<p [innerHTML]="T.F.D_RATE.TXT | translate"></p>
<p>
<div class="action-list">
<a
mat-button
color="primary"
class="action-item action-item--primary"
[href]="cta.url"
target="_blank"
href="https://github.com/super-productivity/super-productivity/blob/master/docs/how-to-rate.md"
><mat-icon>open_in_new</mat-icon>
<strong>{{ T.F.D_RATE.A_HOW | translate }}</strong></a
rel="noopener noreferrer"
(click)="close('rate')"
>
</p>
</div>
</mat-dialog-content>
<mat-icon class="action-item-icon">star</mat-icon>
<span class="action-item-text">{{ cta.labelKey | translate }}</span>
<mat-icon class="action-item-trailing">open_in_new</mat-icon>
</a>
<button
type="button"
class="action-item"
(click)="showFeedback()"
>
<mat-icon class="action-item-icon">chat_bubble_outline</mat-icon>
<span class="action-item-text">{{ T.F.D_RATE.BTN_FEEDBACK | translate }}</span>
<mat-icon class="action-item-trailing">arrow_forward</mat-icon>
</button>
</div>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button
[mat-dialog-close]="true"
mat-stroked-button
color="primary"
>
{{ T.F.D_RATE.BTN_DONT_BOTHER | translate }}
</button>
</mat-dialog-actions>
<mat-dialog-actions class="footer-actions">
<button
mat-button
type="button"
class="opt-out-link"
(click)="close('never')"
>
{{ T.F.D_RATE.BTN_DONT_BOTHER | translate }}
</button>
<span class="spacer"></span>
<button
mat-button
type="button"
(click)="close('later')"
>
{{ T.F.D_RATE.BTN_LATER | translate }}
</button>
</mat-dialog-actions>
} @else {
<h1 mat-dialog-title>{{ T.F.D_RATE.FEEDBACK_TITLE | translate }}</h1>
<mat-dialog-content>
<div class="action-list">
<a
class="action-item"
[href]="discussionsUrl"
target="_blank"
rel="noopener noreferrer"
(click)="close('feedback')"
>
<mat-icon class="action-item-icon">forum</mat-icon>
<span class="action-item-text">
<strong>{{ T.F.D_RATE.FEEDBACK_PUBLIC | translate }}</strong>
<small>{{ T.F.D_RATE.FEEDBACK_PUBLIC_DESC | translate }}</small>
</span>
<mat-icon class="action-item-trailing">open_in_new</mat-icon>
</a>
<a
class="action-item"
[href]="mailtoUrl"
(click)="close('feedback')"
>
<mat-icon class="action-item-icon">mail</mat-icon>
<span class="action-item-text">
<strong>{{ T.F.D_RATE.FEEDBACK_PRIVATE | translate }}</strong>
<small>{{ T.F.D_RATE.FEEDBACK_PRIVATE_DESC | translate }}</small>
</span>
</a>
<a
class="action-item"
[href]="contributingUrl"
target="_blank"
rel="noopener noreferrer"
(click)="close('feedback')"
>
<mat-icon class="action-item-icon">volunteer_activism</mat-icon>
<span class="action-item-text">
<strong>{{ T.F.D_RATE.FEEDBACK_CONTRIBUTE | translate }}</strong>
<small>{{ T.F.D_RATE.FEEDBACK_CONTRIBUTE_DESC | translate }}</small>
</span>
<mat-icon class="action-item-trailing">open_in_new</mat-icon>
</a>
</div>
</mat-dialog-content>
<mat-dialog-actions align="start">
<button
mat-button
type="button"
(click)="showMain()"
>
<mat-icon>arrow_back</mat-icon>
{{ T.F.D_RATE.FEEDBACK_BACK | translate }}
</button>
</mat-dialog-actions>
}

View file

@ -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;
}
}

View file

@ -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<DialogPleaseRateComponent, RateDialogResult>>(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);
}
}

View file

@ -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,
});
});
});
});

View file

@ -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<RateDialogState>;
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)}`;
};

View file

@ -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',
},

View file

@ -171,10 +171,22 @@
}
},
"D_RATE": {
"A_HOW": "كيف وأين يتم التقييم",
"BTN_DONT_BOTHER": "لا تزعجني مرة أخرى",
"TITLE": "🙈 من فضلك سامحنا ، لكن ...",
"TXT": "ستساعد المشروع بشكل كبير من خلال <strong>منحه تقييما جيدا ، إذا كنت ترغب في ذلك!</strong>"
"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": "إنه مشروع <strong>مجاني ومفتوح المصدر</strong> صنعه هواة — بدون تتبّع وبدون إعلانات. تقييم أو رسالة قصيرة تساعد المزيد من الناس على اكتشافه."
},
"DROPBOX": {
"S": {

View file

@ -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 <strong>udělením dobrého hodnocení, pokud se vám líbí!</strong>"
"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 <strong>bezplatný projekt s otevřeným zdrojovým kódem</strong>, 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": {

View file

@ -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 <strong>es gut bewerten, falls Sie es mögen!</strong>"
"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 <strong>kostenloses Open-Source-Projekt</strong>, gebaut von Enthusiasten kein Tracking, keine Werbung. Eine Bewertung oder kurze Nachricht hilft, dass es mehr Leute finden."
},
"DROPBOX": {
"S": {

View file

@ -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 <strong>giving it a good rating, if you like it!</strong>"
"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": {

View file

@ -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 <strong>darle una buena calificación, si te gusta!</strong>"
"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 <strong>gratuito y de código abierto</strong> hecho por entusiastas — sin rastreo ni anuncios. Una calificación o un mensaje breve ayuda a que más personas lo descubran."
},
"DROPBOX": {
"S": {

View file

@ -171,10 +171,22 @@
}
},
"D_RATE": {
"A_HOW": "چگونه و کجا امتیاز دهیم",
"BTN_DONT_BOTHER": "دوباره مزاحم من نکن",
"TITLE": "🙈 لطفا ما را ببخشید، اما...",
"TXT": "اگر دوست دارید، با <strong>دادن امتیاز خوب، به پروژه کمک زیادی خواهید کرد!</strong>"
"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": "این یک پروژه <strong>رایگان و متن‌باز</strong> ساخته‌شده توسط علاقه‌مندان است — بدون ردیابی، بدون تبلیغات. یک امتیاز یا پیام کوتاه کمک می‌کند افراد بیشتری آن را پیدا کنند."
},
"DROPBOX": {
"S": {

View file

@ -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 <strong>antamalla sille hyvän arvion, jos pidät siitä!</strong>"
"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 <strong>ilmainen avoimen lähdekoodin projekti</strong>, jonka tekevät innokkaat harrastajat ei seurantaa eikä mainoksia. Arvostelu tai lyhyt viesti auttaa useampia löytämään sen."
},
"DROPBOX": {
"S": {

View file

@ -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 <strong>l'évaluant positivement, si vous l'aimez !</strong>"
"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 <strong>gratuit et open source</strong> 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": {

View file

@ -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 <strong>dobro ocijeniš, ako ti se sviđa!</strong>"
"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 <strong>besplatan projekt otvorenog koda</strong> koji rade entuzijasti — bez praćenja, bez oglasa. Ocjena ili kratka poruka pomaže da ga otkrije više ljudi."
},
"DROPBOX": {
"S": {

View file

@ -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 <strong>memberikannya peringkat yang bagus, jika Anda menyukainya!</strong>"
"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 <strong>gratis dan sumber terbuka</strong> yang dibuat oleh para penggemar — tanpa pelacakan, tanpa iklan. Penilaian atau pesan singkat membantu lebih banyak orang menemukannya."
},
"DROPBOX": {
"S": {

View file

@ -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 <strong>lasciando una buona recensione, se ti piace!</strong>"
"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 <strong>gratuito e open source</strong> creato da appassionati — niente tracciamento, niente pubblicità. Una recensione o un breve messaggio aiuta più persone a scoprirlo."
},
"DROPBOX": {
"S": {

View file

@ -171,10 +171,22 @@
}
},
"D_RATE": {
"A_HOW": "評価方法と場所",
"BTN_DONT_BOTHER": "二度と気にしないで",
"TITLE": "🙈 ご容赦ください、しかし...",
"TXT": "あなたがそれを好きなら、あなたはそれに良い評価を与えることによって、プロジェクトを大いに助けるでしょう、 <strong>!</strong>"
"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": "これは有志による<strong>無料のオープンソースプロジェクト</strong>です — トラッキングも広告もありません。評価や短いメッセージが、より多くの人に届けるのに役立ちます。"
},
"DROPBOX": {
"S": {

View file

@ -160,10 +160,22 @@
}
},
"D_RATE": {
"A_HOW": "평가 방법 및 위치",
"BTN_DONT_BOTHER": "다시는 나를 괴롭히지 마라",
"TITLE": "🙈 부디 용서해 주세요만...",
"TXT": "당신이 그것을 좋아한다면 <strong>좋은 평가를 주면 프로젝트에 엄청난 도움이 될 것입니다!</strong>"
"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": "<strong>무료 오픈소스 프로젝트</strong>로 애호가들이 만들었습니다 — 추적도 광고도 없습니다. 평가나 짧은 메시지가 더 많은 사람들이 이 앱을 발견하는 데 도움이 됩니다."
},
"DROPBOX": {
"S": {

View file

@ -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 å <strong>gi det en god vurdering, hvis du liker det!</strong>"
"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 <strong>gratis prosjekt med åpen kildekode</strong> laget av entusiaster ingen sporing, ingen reklame. En vurdering eller kort melding hjelper flere å finne det."
},
"DROPBOX": {
"S": {

View file

@ -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 <strong>een goede beoordeling te geven, als je het leuk vindt!</strong>"
"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 <strong>gratis open-sourceproject</strong> gemaakt door enthousiastelingen — geen tracking, geen advertenties. Een beoordeling of korte boodschap helpt meer mensen het te vinden."
},
"DROPBOX": {
"S": {

View file

@ -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, <strong>wystawiając mu dobrą ocenę, jeśli Ci się spodoba!</strong>"
"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 <strong>darmowy projekt open source</strong> tworzony przez pasjonatów — bez śledzenia, bez reklam. Ocena lub krótka wiadomość pomaga większej liczbie osób go znaleźć."
},
"DROPBOX": {
"S": {

View file

@ -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 <strong>dando uma boa avaliação, se gostar dele!</strong>"
"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 <strong>gratuito e de código aberto</strong> feito por entusiastas — sem rastreamento, sem anúncios. Uma avaliação ou uma mensagem curta ajuda mais pessoas a descobri-lo."
},
"DROPBOX": {
"S": {

View file

@ -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 <strong>dando uma boa classificação, se gostar!</strong>"
"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 <strong>gratuito e de código aberto</strong> feito por entusiastas — sem rastreio, sem anúncios. Uma avaliação ou uma mensagem curta ajuda mais pessoas a descobri-lo."
},
"DROPBOX": {
"S": {

View file

@ -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 <strong>acorzi o notă bună, dacă îți place!</strong>"
"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 <strong>gratuit și open-source</strong> 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": {

View file

@ -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 <strong>acorzi o notă bună, dacă îți place!</strong>"
"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 <strong>gratuit și open-source</strong> 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": {

View file

@ -176,10 +176,22 @@
}
},
"D_RATE": {
"A_HOW": "Как и где выставлять оценки",
"BTN_DONT_BOTHER": "Больше не беспокойте меня",
"TITLE": "🙈 Пожалуйста, простите нас, но...",
"TXT": "Вы бы очень помогли проекту, если бы <strong>дали ему хорошую оценку, если он вам нравится!</strong>"
"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": "Это <strong>бесплатный проект с открытым исходным кодом</strong>, созданный энтузиастами — без отслеживания и рекламы. Оценка или короткое сообщение помогает большему числу людей найти приложение."
},
"DROPBOX": {
"S": {

View file

@ -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 <strong>dali dobré hodnotenie, ak sa vám páči!</strong>"
"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 <strong>bezplatný projekt s otvoreným zdrojovým kódom</strong> vytváraný nadšencami žiadne sledovanie, žiadne reklamy. Hodnotenie alebo krátka správa pomáha, aby ho našlo viac ľudí."
},
"DROPBOX": {
"S": {

View file

@ -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 <strong>ge det ett bra betyg, om du gillar det!</strong>"
"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 <strong>gratis projekt med öppen källkod</strong> byggt av entusiaster ingen spårning, inga annonser. Ett betyg eller ett kort meddelande hjälper fler att upptäcka det."
},
"VOICE_REMINDER": {
"FORM": {

View file

@ -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, <strong>iyi bir puan vererek projeye son derece yardımcı olursunuz!</strong>"
"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ış <strong>ücretsiz ve açık kaynaklı</strong> 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": {

View file

@ -194,10 +194,22 @@
}
},
"D_RATE": {
"A_HOW": "Як і де оцінювати",
"BTN_DONT_BOTHER": "Не турбувати більше",
"TITLE": "🙈 Пробачте, будь ласка, але...",
"TXT": "Ви б дуже допомогли проекту, <strong>поставивши йому хорошу оцінку, якщо вам це подобається!</strong>"
"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": "Це <strong>безкоштовний проєкт з відкритим кодом</strong>, створений ентузіастами — без відстеження й реклами. Оцінка або коротке повідомлення допомагає більшій кількості людей знайти його."
},
"FINISH_DAY_BEFORE_EXIT": {
"C": {

View file

@ -181,10 +181,22 @@
}
},
"D_RATE": {
"A_HOW": "如何和在哪裡評分",
"BTN_DONT_BOTHER": "不要再打擾我",
"TITLE": "🙈 請原諒我們,但是...",
"TXT": "如果您喜歡它,<strong>給予好評</strong>將對專案有極大幫助!"
"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": "這是一個由愛好者打造的<strong>免費開源專案</strong>——沒有追蹤、沒有廣告。一個評分或簡短訊息能幫助更多人發現它。"
},
"DROPBOX": {
"S": {

View file

@ -194,10 +194,22 @@
}
},
"D_RATE": {
"A_HOW": "如何以及在哪里评分",
"BTN_DONT_BOTHER": "不要再打扰我",
"TITLE": "🙈 请原谅我们,但是...",
"TXT": "如果您喜欢它,<strong>给它一个好评</strong>,您将极大地帮助这个项目!"
"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": "这是一个由爱好者打造的<strong>免费开源项目</strong> —— 没有追踪,没有广告。一条评分或简短留言能帮助更多人发现它。"
},
"FINISH_DAY_BEFORE_EXIT": {
"C": {