@tomako/tools-runtime 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/package.json +13 -4
  2. package/src/components/tools/workspace/tool-workspace-layout.tsx +1 -1
  3. package/src/constants/related-tools.ts +4 -0
  4. package/src/features/tools/app-icon-resizer/app-icon-resizer.container.tsx +15 -2
  5. package/src/features/tools/app-icon-resizer/app-icon-resizer.spec.ts +1 -1
  6. package/src/features/tools/app-icon-resizer/widget/app-icon-resizer.tsx +54 -11
  7. package/src/features/tools/app-icon-resizer/widget/platform-icons.tsx +2 -5
  8. package/src/features/tools/mrr-calculator/mrr-calculator.container.tsx +23 -0
  9. package/src/features/tools/mrr-calculator/mrr-calculator.spec.ts +15 -0
  10. package/src/features/tools/mrr-calculator/widget/calculations.ts +74 -0
  11. package/src/features/tools/mrr-calculator/widget/index.ts +1 -0
  12. package/src/features/tools/mrr-calculator/widget/mrr-calculator.tsx +581 -0
  13. package/src/features/tools/registry.ts +6 -0
  14. package/src/features/tools/runtime-registry.ts +4 -0
  15. package/src/features/tools/shared/create-standard-landing-container.tsx +35 -5
  16. package/src/features/tools/shared/tool-page-shell.tsx +4 -4
  17. package/src/features/tools/shared/tool-standard-landing-sections.tsx +262 -52
  18. package/src/features/tools/spec-registry.ts +2 -0
  19. package/src/features/tools/widget-registry.ts +2 -0
  20. package/src/i18n/messages/en/tools/app-icon-resizer.ts +90 -62
  21. package/src/i18n/messages/en/tools/build-in-public-story-generator.ts +1 -1
  22. package/src/i18n/messages/en/tools/index.ts +2 -0
  23. package/src/i18n/messages/en/tools/mrr-calculator.ts +202 -0
  24. package/src/i18n/messages/en/tools-ui.ts +3 -2
  25. package/src/i18n/messages/zh/page/tools.ts +2 -3
  26. package/src/i18n/messages/zh/tools/app-icon-resizer.ts +90 -62
  27. package/src/i18n/messages/zh/tools/build-in-public-story-generator.ts +1 -1
  28. package/src/i18n/messages/zh/tools/index.ts +2 -0
  29. package/src/i18n/messages/zh/tools/mrr-calculator.ts +112 -0
  30. package/src/i18n/messages/zh/tools-ui.ts +3 -2
  31. package/src/i18n/messages/zh-tw/tools/app-icon-resizer.ts +90 -62
  32. package/src/i18n/messages/zh-tw/tools/build-in-public-story-generator.ts +1 -1
  33. package/src/i18n/messages/zh-tw/tools/index.ts +2 -0
  34. package/src/i18n/messages/zh-tw/tools/mrr-calculator.ts +52 -0
  35. package/src/i18n/messages/zh-tw/tools-ui.ts +3 -2
  36. package/src/lib/tools/resolve-tool-locale-copy.ts +7 -1
@@ -1,9 +1,9 @@
1
1
  const appIconResizer = {
2
2
  meta: {
3
- title: "App Icon 切圖:iOS 與 Android 尺寸包",
3
+ title: "App Icon 尺寸產生器:iOS 與 Android",
4
4
  description:
5
- "上傳一張 App Icon,本地切出 iOS / App Store / Google Play / Android 尺寸包,並打包 ZIP 下載。",
6
- intro: " App 上架和工程交付準備圖標資源。上傳 1024px+ 方形源圖,選擇 Apple、Google Play 或雙平臺尺寸包,源圖不上傳服務器。",
5
+ "上傳方形 App Icon,在瀏覽器本地產生 Xcode AppIcon、Google Play 512 Android launcher 圖示包,預覽後下載 ZIP",
6
+ intro: "上傳 1024px+ 方形原圖,本地產生 Xcode AppIcon、Google Play 圖示和 Android legacy launcher 檔案。",
7
7
  category: "App 上架工具",
8
8
  keywords: [
9
9
  "app icon 切圖",
@@ -19,48 +19,61 @@ const appIconResizer = {
19
19
  guide: {
20
20
  heroVisualAlt:
21
21
  "App Icon 資源包視覺圖,展示一個源圖標導出為商店提交圖標、Xcode 資源和 Android launcher 文件。",
22
- workspaceHeading: "App Icon 切圖",
22
+ workspaceHeading: "App Icon 尺寸包產生器",
23
23
  workspaceHint:
24
- "上傳源圖,本地生成商店與工程圖標 ZIP。",
24
+ "一張原圖,本地產生商店與工程圖示 ZIP。",
25
25
  workspaceBadge: "PNG + ZIP",
26
26
  standard: {
27
27
  benefits: {
28
- title: "這個 App Icon 切圖工具能帶來什麼",
28
+ title: "為什麼用這個工具",
29
29
  cards: [
30
30
  {
31
- title: "一張源圖覆蓋多端",
32
- body: "一次生成 Xcode AppIcon、App Store 1024、Google Play 512 Android mipmap,減少重複導出。",
31
+ title: "一次產生交付檔案",
32
+ body: "不用逐張建立畫板和匯出。一次產生 Xcode AppIcon、Google Play 512 Android legacy launcher 檔案。",
33
33
  },
34
34
  {
35
- title: "尺寸與目錄自動整理",
36
- body: " Apple、Google Play 或雙平臺分組、命名和打包,設計與研發更容易拿到正確文件。",
35
+ title: "目錄和命名已整理",
36
+ body: "商店上傳圖、Xcode 資源與 Android 工程檔案按用途分組,下載後不用自己建目錄或逐張改名。",
37
37
  },
38
38
  {
39
- title: "本地生成,先看再下",
40
- body: "源圖不上傳服務器;先在透明網格中檢查裁切、邊緣和體積風險,再下載 PNG 或 ZIP。",
39
+ title: "先預覽再下載",
40
+ body: "先檢查透明背景、裁切方式和檔案大小風險。切圖和 ZIP 打包都在目前瀏覽器完成。",
41
41
  },
42
42
  ],
43
43
  },
44
- imageTextSections: [
45
- {
46
- id: "icon-package",
47
- title: "一張源圖\n生成完整尺寸包",
48
- body: [
49
- "App Icon 切圖最容易出錯的地方不是縮放,而是尺寸、目錄和命名混亂。這個工具把 iOS AppIcon.appiconset、App Store 1024、Google Play 512 Android mipmap 分組輸出。",
50
- "源圖只在瀏覽器本地讀取,生成後你可以直接下載 ZIP,也可以篩選平臺逐個複核 PNG。",
51
- ],
52
- image: {
53
- src: "/tools/app-icon-resizer-section-primary-8bit-v3.webp",
54
- alt: "App Icon 源圖生成平臺圖標尺寸包的 8bit 場景圖",
44
+ outputPreview: {
45
+ eyebrow: "範例輸出",
46
+ title: "下載包裡有什麼",
47
+ intro: "選擇雙平台後,檔案會按實際交付位置分組。下面是目前工具會產生的目錄和檔案。",
48
+ inputLabel: "範例輸入",
49
+ input: "一張 1024 × 1024 方形 PNG,選擇 Apple + Google Play / Android",
50
+ outputLabel: "ZIP 主要內容",
51
+ fields: [
52
+ {
53
+ label: "Apple/AppIcon.appiconset",
54
+ body: "iPhone、iPad ios-marketing 相容尺寸,附 Contents.json。",
55
55
  },
56
- imageFirst: true,
57
- },
56
+ {
57
+ label: "Apple/AppStoreIcon-1024.png",
58
+ body: "供團隊在上架前檢查主體、留白和品牌一致性的 1024px 副本。",
59
+ },
60
+ {
61
+ label: "GooglePlay/app-icon-512.png",
62
+ body: "Play Console store listing 使用的 512 × 512 PNG。",
63
+ },
64
+ {
65
+ label: "Android/res/mipmap-*",
66
+ body: "mdpi 到 xxxhdpi 的 legacy launcher PNG;不含 Adaptive Icon 圖層。",
67
+ },
68
+ ],
69
+ },
70
+ imageTextSections: [
58
71
  {
59
72
  id: "platform-scope",
60
- title: "按平臺選擇\n不混淆上傳圖和工程圖",
73
+ title: "下載後怎麼使用",
61
74
  body: [
62
- "Apple、Google Play 和 Android 工程資源不是同一個文件。Apple 側主要交給 Xcode 資產目錄,Google Play 需要 512 x 512 商店圖,Android launcher 還會按密度分目錄。",
63
- "選擇平臺範圍後,結果區會按平臺篩選,方便設計、研發和 ASO 團隊確認自己該拿哪一組文件。",
75
+ " Apple/AppIcon.appiconset 匯入 Xcode asset catalog,再隨 build 提交;GooglePlay/app-icon-512.png 用於 Play Console store listing。",
76
+ "Android/res/mipmap-* legacy launcher 工程資源。如果專案使用 Adaptive Icon,仍需在 Android Studio 設定前景、背景和可選的 monochrome 圖層。",
64
77
  ],
65
78
  image: {
66
79
  src: "/tools/app-icon-resizer-section-variation-8bit-v3.webp",
@@ -69,10 +82,10 @@ const appIconResizer = {
69
82
  },
70
83
  {
71
84
  id: "handoff-review",
72
- title: "先預覽再下載\n減少上架前返工",
85
+ title: "使用前需要知道",
73
86
  body: [
74
- "結果區會用透明網格展示每個 PNG,避免把透明像素誤看成灰底。非方形圖會居中裁切,過小源圖會被攔截。",
75
- "下載後的 README 會說明每個目錄的使用位置,並提醒圓角、陰影、adaptive icon、版權和平臺最新規則仍需要人工複核。",
87
+ "非方形圖片會置中裁成方形,不會拉伸。正式交付應優先使用方形滿版源圖,也不要預先加入圓角或外陰影。",
88
+ "圖片讀取、縮放和 ZIP 打包都在瀏覽器本地完成。正式發布前仍需複核平台最新規則、品牌版權,以及淺色和深色背景下的辨識度。",
76
89
  ],
77
90
  image: {
78
91
  src: "/tools/app-icon-resizer-section-support-8bit-v3.webp",
@@ -82,31 +95,56 @@ const appIconResizer = {
82
95
  },
83
96
  ],
84
97
  generation: {
85
- title: "App Icon\n切圖流程",
98
+ title: "三步完成",
86
99
  imageAlt: "上傳 App Icon 後選擇平臺、裁切預覽並導出 ZIP 的 8bit 流程圖",
87
100
  ctaLabel: "生成圖標資源包",
88
101
  steps: [
89
102
  {
90
- title: "上傳一張源圖",
91
- body: "從設計源文件導出方形滿版 PNG,或上傳 JPG / WebPApple 或雙平臺包需要源圖短邊至少 1024px。",
103
+ title: "上傳並選擇平台",
104
+ body: "上傳 PNGJPG WebP,再選擇 Apple、Google Play / Android 或雙平台。Apple 包需要原圖短邊至少 1024px。",
92
105
  },
93
106
  {
94
- title: "選擇平臺範圍",
95
- body: "選擇 AppleGoogle Play 或雙平臺。工具會自動匹配對應尺寸清單和目錄結構。",
107
+ title: "本地生成尺寸包",
108
+ body: "瀏覽器完成裁切、縮放、命名和目錄整理,同時生成 PNGContents.json README。",
96
109
  },
97
110
  {
98
- title: "生成 PNG 與 README",
99
- body: "瀏覽器本地裁切、縮放、保留透明像素,並寫入說明文件,不把源圖上傳到服務器。",
111
+ title: "預覽並下載 ZIP",
112
+ body: "在結果區篩選平台、檢查透明網格和檔案大小風險,然後下載完整 ZIP 或單個 PNG。",
113
+ },
114
+ ],
115
+ },
116
+ referenceTable: {
117
+ title: "實際輸出與使用位置",
118
+ intro: "現代 Xcode 可以從單張 1024px 圖示產生較小變體;Tomako 仍提供完整相容型 AppIcon.appiconset,方便接入現有專案和團隊交付。",
119
+ mobileHint: "表格可左右滑動,查看完整檔案去向。",
120
+ columns: ["輸出組", "包含內容", "目前用途", "使用位置"],
121
+ rows: [
122
+ {
123
+ label: "Xcode AppIcon",
124
+ cells: ["20–1024px 相容尺寸,附 Contents.json", "iOS / iPadOS 工程圖示", "Xcode asset catalog"],
125
+ },
126
+ {
127
+ label: "Apple 1024 副本",
128
+ cells: ["Apple/AppStoreIcon-1024.png", "團隊視覺複核,不是另一套固定上傳流程", "上架前檢查主體與留白"],
129
+ },
130
+ {
131
+ label: "Google Play",
132
+ cells: ["GooglePlay/app-icon-512.png", "512 × 512 PNG;超過 1024KB 時提示", "Play Console store listing"],
100
133
  },
101
134
  {
102
- title: "複核後下載 ZIP",
103
- body: "在結果區篩選平臺、檢查透明網格和體積風險,然後下載完整 ZIP 或單個 PNG",
135
+ label: "Android legacy launcher",
136
+ cells: ["48 / 72 / 96 / 144 / 192px", "相容型 launcher PNG", "Android/res/mipmap-*"],
137
+ },
138
+ {
139
+ label: "交付說明",
140
+ cells: ["README.txt", "目錄用途與邊界說明", "設計、工程與 ASO 交接"],
104
141
  },
105
142
  ],
143
+ note: "Google Play 圖示還需符合平台的 PNG、檔案大小和內容規範。目前不產生 Android Adaptive Icon 的 foreground、background 或 monochrome 圖層。",
106
144
  },
107
145
  faqIntro:
108
- "這些問題幫助你判斷源圖是否合適、生成的文件怎麼用,以及哪些平臺邊界仍要手動複核。",
109
- faqCtaLabel: "查看邊界",
146
+ "先確認原圖要求和檔案去向,再判斷這套輸出是否適合你的發布流程。",
147
+ faqCtaLabel: "回到工作台",
110
148
  },
111
149
  whatYouGetHeading: "生成後會得到什麼",
112
150
  valueVisualAlt: "整理好的 App Icon 文件包,包含 Xcode 資源目錄、商店提交圖標、Android 工程目錄和 ZIP 下載包。",
@@ -192,44 +230,34 @@ const appIconResizer = {
192
230
  faqHeading: "常見問題",
193
231
  faqItems: [
194
232
  {
195
- question: "上傳的 App Icon 會保存到服務器嗎?",
233
+ question: "原圖應該準備成什麼格式和尺寸?",
196
234
  answer:
197
- "不會。當前工具在瀏覽器本地讀取圖片、繪製 canvas、生成 PNG 和 ZIP;刷新頁面後文件狀態會消失,源圖不會上傳到服務器。",
235
+ "建議使用 1024 × 1024 或更大的方形 PNG。JPGWebP 也支援;只生成 Google Play / Android 時,原圖短邊至少需要 512px。",
198
236
  },
199
237
  {
200
- question: "生成的圖標能直接上傳到 App Store 和 Google Play 嗎?",
238
+ question: "上傳的 App Icon 會儲存到伺服器嗎?",
201
239
  answer:
202
- "GooglePlay/app-icon-512.png 面向 Google Play Console 的 App icon 上傳要求。Apple 側更準確的路徑是把 AppIcon.appiconset 放入 Xcode,隨 build 提交到 App Store Connect。",
240
+ "不會。圖片讀取、canvas 切圖和 ZIP 打包都在瀏覽器本地完成。重新整理頁面後檔案狀態會消失,原圖不會上傳伺服器。",
203
241
  },
204
242
  {
205
- question: "源圖應該準備成什麼格式和尺寸?",
243
+ question: "生成的圖示能直接用於 App Store 和 Google Play 嗎?",
206
244
  answer:
207
- "推薦上傳 1024 x 1024 或更大的方形 PNG。JPG WebP 也支持,但正式交付前建議從設計源文件導出方形滿版圖,避免壓縮、透明或邊緣問題。",
245
+ "可以作為工程接入和商店上傳素材,但正式發布前仍需複核。GooglePlay/app-icon-512.png 用於 Play Console;Apple/AppIcon.appiconset 應放入 Xcode,再隨 build 提交到 App Store Connect。",
208
246
  },
209
247
  {
210
248
  question: "為什麼不自動加圓角或陰影?",
211
249
  answer:
212
- "商店和系統會應用自己的遮罩、圓角或陰影。提前把圖標做圓角可能導致二次裁切、邊緣不齊或不符合平臺要求。",
213
- },
214
- {
215
- question: "源圖不是方形怎麼辦?",
216
- answer:
217
- "當前會按中心裁成方形,不會拉伸圖片。正式交付建議回到設計源文件導出方形滿版圖,避免主體偏移或邊緣被裁掉。",
250
+ "不用提前加入。商店和系統會套用自己的遮罩、圓角或陰影,預先處理可能造成二次裁切或邊緣不齊。",
218
251
  },
219
252
  {
220
- question: "透明背景的圖標會怎麼處理?",
253
+ question: "原圖不是方形或帶透明背景怎麼辦?",
221
254
  answer:
222
- "工具會保留透明像素,並在結果預覽裡用透明網格展示。正式上架前建議確認圖標在淺色、深色和平臺遮罩下都能被清楚識別。",
255
+ "會置中裁成方形,不會拉伸圖片。透明像素會保留;正式發布前仍要檢查主體位置、裁切邊緣和不同背景下的辨識度。",
223
256
  },
224
257
  {
225
258
  question: "這個工具會生成 Android adaptive icon 嗎?",
226
259
  answer:
227
- "不會。當前輸出 Google Play 512 和 legacy launcher mipmap PNG,不生成 adaptive icon 的 foreground/background XML 組合。需要 adaptive icon 時仍要在 Android 工程中按品牌規範配置。",
228
- },
229
- {
230
- question: "圖片太小會怎樣?",
231
- answer:
232
- "選擇 Apple 或雙平臺時,源圖短邊低於 1024px 會被攔截;只生成 Google Play / Android 時,短邊低於 512px 會被攔截。Google Play 512 圖標超過 1024KB 時會顯示風險提示。",
260
+ "不會。目前輸出 Google Play 512 和 legacy launcher mipmap PNG,不生成 adaptive icon 的 foreground/background XML。你需要在 Android 工程裡另外設定。",
233
261
  },
234
262
  ],
235
263
  ctaPrimary: "繼續做商店截圖",
@@ -153,7 +153,7 @@ const buildInPublicStoryGenerator = {
153
153
  stageLabel: "當前階段",
154
154
  productContextLabel: "產品背景",
155
155
  productContextPlaceholder:
156
- "Tomako 是面向獨立開發者的 AI GTM OS,幫助把產品上下文轉成渠道策略、發佈素材和增長動作。",
156
+ "Tomako 是軟體團隊 24 小時在線的 AI CMO,把產品與市場上下文轉成有優先順序、可審核的內容、KOL、SEO、用戶回饋、發佈和競品情報工作。",
157
157
  thisWeekLabel: "這周真實進展",
158
158
  thisWeekPlaceholder:
159
159
  "例如:我們用 Tomako 生成了冷啟動渠道排序,發現 Reddit 適合問具體判斷,Product Hunt 暫時不適合直接衝發佈。",
@@ -14,6 +14,7 @@ import marketForecastReport from "./market-forecast-report";
14
14
  import kokoCodexAssistant from "./koko-codex-assistant";
15
15
  import logoGenerator from "./logo-generator";
16
16
  import millionUserGrowthTest from "./million-user-growth-test";
17
+ import mrrCalculator from "./mrr-calculator";
17
18
  import ogImageGenerator from "./og-image-generator";
18
19
  import pitchDeckGenerator from "./pitch-deck-generator";
19
20
  import productAgreementGenerator from "./product-agreement-generator";
@@ -59,6 +60,7 @@ const toolsPages = {
59
60
  kokoCodexAssistant,
60
61
  logoGenerator,
61
62
  millionUserGrowthTest,
63
+ mrrCalculator,
62
64
  ogImageGenerator,
63
65
  appStoreScreenshotGenerator,
64
66
  twitterGifDownloader,
@@ -0,0 +1,52 @@
1
+ const mrrCalculator = {
2
+ meta: {
3
+ title: "SaaS MRR 計算器|每月經常性收入計算",
4
+ description: "用客戶資料計算 MRR 和 ARR,或根據公開網站流量、方案價格和可調整假設估算 SaaS MRR。",
5
+ intro: "把月繳、季繳或年繳訂閱統一換算為每月經常性收入,也可以切換到公開資料估算模式。",
6
+ category: "SaaS 指標工具",
7
+ keywords: ["MRR 計算器", "每月經常性收入計算器", "MRR 公式", "如何計算 MRR", "MRR 轉 ARR", "SaaS MRR 計算器"],
8
+ inputSignal: "客戶與計費資料,或公開流量與方案價格",
9
+ outputSignal: "MRR、ARR、每月 ARPA、成長率或公開資料估算",
10
+ boundarySignal: "瀏覽器本機計算;估算結果僅供方向判斷,並非公司揭露收入",
11
+ },
12
+ guide: {
13
+ workspaceHeading: "SaaS MRR 計算器",
14
+ workspaceHint: "用已知客戶資料計算每月經常性收入,或切換到估算模式,用公開流量和方案價格粗略判斷 SaaS MRR。",
15
+ standard: {
16
+ benefits: { title: "這個 MRR 計算器會回傳什麼", cards: [
17
+ { title: "同時得到 MRR 和 ARR", body: "無需製作試算表,直接查看每月經常性收入、年度經常性收入和每月 ARPA。" },
18
+ { title: "自動統一計費週期", body: "輸入月繳、季繳或年繳價格,計算器會先統一換算到每月口徑。" },
19
+ { title: "也能粗略評估競品", body: "不知道客戶數時,用公開流量、方案價格和可調整假設得到明確標註的估算結果。" },
20
+ ] },
21
+ imageTextSections: [
22
+ { id: "choose-the-right-mrr-method", title: "選擇正確的\nMRR 計算方式", body: [{ text: "想計算自己產品的 MRR 或 ARR 時,使用預設的「計算 MRR」。填寫活躍付費客戶數、每位客戶的經常性金額和計費週期,工具會直接計算結果。", highlights: ["計算 MRR"] }, { text: "想粗略了解競品或其他 SaaS 的收入量級時,切換到「估算 SaaS MRR」。根據公開網站流量和方案價格填寫估算條件;結果只用於方向判斷,不是對方揭露的收入。", highlights: ["估算 SaaS MRR"] }], image: { src: "/tools/mrr-calculator-section-steps-8bit.webp", alt: "像素風工作台比較用客戶資料計算 MRR 與用公開流量和方案價格估算 SaaS MRR。" }, imageFirst: true, hideImageOnMobile: true },
23
+ { id: "monthly-recurring-revenue-formula", title: "如何計算\n每月經常性收入", body: [{ text: "每月經常性收入公式是:MRR = 活躍付費客戶數 × 每月 ARPA。季繳經常性金額先除以 3,年繳金額先除以 12,再乘以客戶數。", highlights: ["MRR = 活躍付費客戶數 × 每月 ARPA"] }, "例如,12 位客戶每年支付 1,200 美元,每月 ARPA 為 100 美元,MRR 為 1,200 美元,ARR 為 14,400 美元。若上月 MRR 為 1,000 美元,月增率是(1,200 − 1,000)÷ 1,000 = 20%。"], image: { src: "/tools/mrr-calculator-section-primary-8bit.webp", alt: "像素風 SaaS 帳本把月繳、季繳和年繳訂閱統一換算成 MRR。" } },
24
+ { id: "estimate-saas-mrr", title: "用公開資料\n估算 SaaS MRR", body: ["估算模式先用「造訪量 × 可用於獲客的造訪比例 × 訪客轉付費率」估算每月新增付費客戶,再用平均付費週期估算活躍客戶數,最後乘以換算後的每月方案價格。", "重複造訪、現有客戶、獲客通路、轉換率、方案結構和流失仍然未知。比較多個產品時應保持假設一致,商業模式不同時再調整;結果只適合方向判斷。"], image: { src: "/tools/mrr-calculator-section-variation-8bit.webp", alt: "像素風公開流量圖和方案價格卡片進入明確標註的 SaaS MRR 估算結果。" }, imageFirst: true },
25
+ ],
26
+ editorialSections: [
27
+ { id: "what-counts-as-mrr", title: "哪些收入應計入每月經常性收入", body: ["MRR 是統一到單月口徑的經常性訂閱收入。應計入目前合約下持續發生的有效方案收入,季繳或年繳金額需要先換算到每月。", "不要計入一次性設定費、導入費、專業服務、硬體、稅費和其他非經常性收款。如果涉及折扣、退款、用量計費、擴張、收縮或流失,應使用帳務系統資料和更完整的收入模型。"] },
28
+ { id: "common-mrr-calculation-mistakes", title: "常見的 MRR 計算錯誤", body: ["不要把整筆年繳收入全部放進一個月,也不要計入一次性收入,或把新增 MRR 當成公司總 MRR。涉及多個方案時,應分別計算後相加,或使用加權平均月價,不要假設客戶平均分布。", "在估算模式中,不要把所有網站造訪量或直接流量都當成新客戶。流量可能包含回訪者、現有客戶、員工和重複工作階段,因此可用於獲客的造訪比例必須保持為明確假設。", "最重要的是,不要把 Estimated MRR 情境寫成競品真實收入。公開流量和價格無法揭示真實客戶數、折扣、留存和獲客通路。"] },
29
+ { id: "use-mrr-and-arr-results", title: "如何使用 MRR 和 ARR 結果", body: ["核對客戶數、經常性金額和計費週期後,可以把計算 MRR 用於營運檢查、每月報告或方案情境測試。填寫上月 MRR 可以查看月增率,把 MRR 轉成 ARR 可以得到年化經常性收入視角。", "估算 MRR 只適合競品方向性比較。比較不同產品時保持同一組假設,記錄結果依據,並在流量或價格變化後重新計算。", "這些結果可以繼續用於流失率、留存和 LTV:CAC 分析,但不屬於會計報表、財務建議或估值意見。"] },
30
+ ],
31
+ faqIntro: "補充回答多方案、零分母、直接流量、估算邊界和瀏覽器本機資料處理問題。", faqCtaLabel: "使用計算器",
32
+ },
33
+ faqHeading: "MRR 計算器常見問題",
34
+ faqItems: [
35
+ { question: "這個 MRR 計算器如何使用?", answer: "想計算自己產品的 MRR 或 ARR 時,保留預設的「計算 MRR」,填寫活躍付費客戶數、每位客戶的經常性金額和計費週期。想粗略了解競品或其他 SaaS 的收入量級時,切換到「估算 SaaS MRR」,根據公開網站流量和方案價格填寫估算條件。前者是依你的輸入直接計算;後者只是方向性估算。" },
36
+ { question: "不同方案可以一起計算嗎?", answer: "V1 接收一個混合平均經常性金額。你可以分別計算各方案後相加,或在知道方案比例時先算出加權平均月價。" },
37
+ { question: "上月 MRR 為零時怎麼辦?", answer: "工具仍會回傳本月 MRR 和 ARR,但不會顯示月增率,因為分母為零時百分比成長沒有可靠含義。" },
38
+ { question: "可以把直接流量當成新客戶嗎?", answer: "不可以。直接流量可能包含回訪者、現有客戶、員工、書籤造訪和無法歸因的工作階段。估算時只應計入一部分可用於獲客的造訪量。" },
39
+ { question: "SaaS MRR 估算有多準確?", answer: "它只適合方向判斷,不是精確結果。是否有參考價值取決於流量、價格、轉換率和付費週期假設是否接近被評估產品。" },
40
+ { question: "這個估算屬於財務建議或估值意見嗎?", answer: "不屬於。它只是基於公開輸入和你的假設得到的情境,不應作為會計證據、公司收入事實、財務建議或估值結論。" },
41
+ { question: "輸入的資料會離開瀏覽器嗎?", answer: "不會。目前版本在瀏覽器內完成計算,不上傳輸入值,也不需要註冊帳號。" },
42
+ ],
43
+ },
44
+ widget: {
45
+ calculateMode: "計算 MRR", estimateMode: "估算 SaaS MRR", modeSwitchLabel: "切換計算與估算 MRR 模式", calculateHint: "使用已知付費客戶和訂閱資料,得到計算結果。", estimateHint: "使用公開流量和價格進行粗略估算,並非公司揭露收入。",
46
+ activeCustomers: "活躍付費客戶數", recurringAmount: "每位客戶的經常性金額", billingPeriod: "計費週期", previousMrr: "上月 MRR", optional: "選填", addPreviousMrr: "加入上月 MRR(選填)", currency: "幣別", monthlyVisits: "估算的網站每月造訪量", planPrice: "有代表性的公開方案價格", showAssumptions: "調整估算假設", hideAssumptions: "收起估算假設", assumptionNote: "這些只是起始假設,不是產業基準。請根據被評估產品進行調整。", eligibleVisitShare: "可用於獲客的造訪比例(%)", visitorToPaidRate: "訪客轉付費率(%)", averagePaidLifetime: "平均付費週期(月)",
47
+ periods: { month: "月繳", quarter: "季繳", year: "年繳" }, calculatedLabel: "計算結果", estimatedLabel: "估算結果", calculatedResultTitle: "每月經常性收入", estimatedResultTitle: "SaaS 收入方向性估算", calculatedMrr: "計算 MRR", estimatedMrr: "估算 MRR", arr: "ARR", estimatedArr: "估算 ARR", monthlyArpa: "每月 ARPA", monthlyPlanPrice: "每月方案價格", momGrowth: "MRR 月增率", newPaidCustomers: "每月新增付費客戶", activePaidCustomers: "估算活躍付費客戶", formula: "算式檢查", perMonth: "每月", assumptionsUsed: "本次使用的假設", notAvailable: "無法計算",
48
+ calculatedGuidance: "只計入經常性訂閱收入,排除一次性費用、稅費和非經常性服務。", estimateDisclaimer: "僅為公開資料估算。實際流量品質、轉換率、方案結構、流失和收入可能不同。", copyResult: "複製結果", copied: "已複製", reset: "重設", fixInputsTitle: "檢查標紅的輸入項", fixInputsBody: "輸入有效數值後,結果會自動更新。", errors: { nonNegative: "請輸入零或正數。", positive: "請輸入大於零的數值。", percent: "請輸入 0 到 100 之間的百分比。" },
49
+ },
50
+ } as const;
51
+
52
+ export default mrrCalculator;
@@ -492,8 +492,9 @@ const toolsUi = {
492
492
  downloadZip: "下載 ZIP",
493
493
  selectedTitle: "選中圖標",
494
494
  downloadPng: "下載 PNG",
495
- outputEmptyTitle: "先上傳源圖並選擇平臺",
496
- outputEmptyHint: "上傳 1024px+ 方形源圖,選擇 Apple、Google Play 或雙平臺資源包,然後生成。完成後這裡會展示 ZIP 下載和圖標預覽。",
495
+ outputEmptyTitle: "上傳後在這裡檢查檔案包",
496
+ outputEmptyHint: "目前的平台選擇會生成下列主要目錄。上傳源圖並生成後,這裡會切換為實際 PNG 預覽和 ZIP 下載。",
497
+ outputExampleLabel: "app-icon-assets.zip 範例結構",
497
498
  platforms: {
498
499
  all: "App Store + Google Play",
499
500
  apple: "Apple App Store / iOS",
@@ -5,6 +5,7 @@ import {
5
5
  } from "../../i18n/locale-fallback";
6
6
  import type { AppLocale } from "../../i18n/locale";
7
7
  import enToolsPages from "../../i18n/messages/en/tools";
8
+ import zhTwToolsPages from "../../i18n/messages/zh-tw/tools";
8
9
  import zhToolsPages from "../../i18n/messages/zh/tools";
9
10
  import type { ToolLocaleCopy, ToolSpec } from "../../features/tools/types";
10
11
 
@@ -13,6 +14,10 @@ import { resolveToolsPagesKey } from "./tool-message-keys";
13
14
  type ToolPageModule = { meta?: ToolLocaleCopy };
14
15
 
15
16
  function toolsPagesForPrimary(locale: AppLocale): Record<string, ToolPageModule> {
17
+ if (locale === "zh-tw") {
18
+ return zhTwToolsPages as unknown as Record<string, ToolPageModule>;
19
+ }
20
+
16
21
  return (resolvePrimaryLocale(locale) === "zh"
17
22
  ? zhToolsPages
18
23
  : enToolsPages) as unknown as Record<string, ToolPageModule>;
@@ -62,12 +67,13 @@ export function resolveToolSpecLocales(spec: ToolSpec): PartialLocaleRecord<Tool
62
67
 
63
68
  const zh = getToolI18nMeta(spec.slug, "zh") ?? spec.locales?.zh;
64
69
  const en = getToolI18nMeta(spec.slug, "en") ?? spec.locales?.en;
70
+ const zhTw = getToolI18nMeta(spec.slug, "zh-tw") ?? spec.locales?.["zh-tw"];
65
71
 
66
72
  if (!zh || !en) {
67
73
  throw new Error(`Missing zh/en locale copy for tool "${spec.slug}"`);
68
74
  }
69
75
 
70
- return { zh, en };
76
+ return zhTw ? { zh, en, "zh-tw": zhTw } : { zh, en };
71
77
  }
72
78
 
73
79
  export function withResolvedLocales(spec: ToolSpec): ToolSpec {