@voxendar/shared 0.2.0 → 0.4.0
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.
- package/dist/capture/audio.d.ts +16 -0
- package/dist/capture/audio.d.ts.map +1 -0
- package/dist/capture/audio.js +22 -0
- package/dist/capture/audio.js.map +1 -0
- package/dist/capture/fields.d.ts +87 -0
- package/dist/capture/fields.d.ts.map +1 -0
- package/dist/capture/fields.js +171 -0
- package/dist/capture/fields.js.map +1 -0
- package/dist/constants.d.ts +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +1 -0
- package/dist/constants.js.map +1 -1
- package/dist/i18n/copy/ar-SA.d.ts +176 -0
- package/dist/i18n/copy/ar-SA.d.ts.map +1 -0
- package/dist/i18n/copy/ar-SA.js +194 -0
- package/dist/i18n/copy/ar-SA.js.map +1 -0
- package/dist/i18n/copy/de-DE.d.ts +176 -0
- package/dist/i18n/copy/de-DE.d.ts.map +1 -0
- package/dist/i18n/copy/de-DE.js +196 -0
- package/dist/i18n/copy/de-DE.js.map +1 -0
- package/dist/i18n/copy/en-US.d.ts +190 -0
- package/dist/i18n/copy/en-US.d.ts.map +1 -0
- package/dist/i18n/copy/en-US.js +223 -0
- package/dist/i18n/copy/en-US.js.map +1 -0
- package/dist/i18n/copy/es-MX.d.ts +176 -0
- package/dist/i18n/copy/es-MX.d.ts.map +1 -0
- package/dist/i18n/copy/es-MX.js +189 -0
- package/dist/i18n/copy/es-MX.js.map +1 -0
- package/dist/i18n/copy/fr-FR.d.ts +176 -0
- package/dist/i18n/copy/fr-FR.d.ts.map +1 -0
- package/dist/i18n/copy/fr-FR.js +190 -0
- package/dist/i18n/copy/fr-FR.js.map +1 -0
- package/dist/i18n/copy/he-IL.d.ts +176 -0
- package/dist/i18n/copy/he-IL.d.ts.map +1 -0
- package/dist/i18n/copy/he-IL.js +190 -0
- package/dist/i18n/copy/he-IL.js.map +1 -0
- package/dist/i18n/copy/hi-IN.d.ts +176 -0
- package/dist/i18n/copy/hi-IN.d.ts.map +1 -0
- package/dist/i18n/copy/hi-IN.js +191 -0
- package/dist/i18n/copy/hi-IN.js.map +1 -0
- package/dist/i18n/copy/ja-JP.d.ts +176 -0
- package/dist/i18n/copy/ja-JP.d.ts.map +1 -0
- package/dist/i18n/copy/ja-JP.js +192 -0
- package/dist/i18n/copy/ja-JP.js.map +1 -0
- package/dist/i18n/copy/ko-KR.d.ts +176 -0
- package/dist/i18n/copy/ko-KR.d.ts.map +1 -0
- package/dist/i18n/copy/ko-KR.js +192 -0
- package/dist/i18n/copy/ko-KR.js.map +1 -0
- package/dist/i18n/copy/pt-BR.d.ts +176 -0
- package/dist/i18n/copy/pt-BR.d.ts.map +1 -0
- package/dist/i18n/copy/pt-BR.js +187 -0
- package/dist/i18n/copy/pt-BR.js.map +1 -0
- package/dist/i18n/copy/ru-RU.d.ts +176 -0
- package/dist/i18n/copy/ru-RU.d.ts.map +1 -0
- package/dist/i18n/copy/ru-RU.js +191 -0
- package/dist/i18n/copy/ru-RU.js.map +1 -0
- package/dist/i18n/copy/zh-CN.d.ts +176 -0
- package/dist/i18n/copy/zh-CN.d.ts.map +1 -0
- package/dist/i18n/copy/zh-CN.js +189 -0
- package/dist/i18n/copy/zh-CN.js.map +1 -0
- package/dist/i18n/copy/zh-TW.d.ts +176 -0
- package/dist/i18n/copy/zh-TW.d.ts.map +1 -0
- package/dist/i18n/copy/zh-TW.js +196 -0
- package/dist/i18n/copy/zh-TW.js.map +1 -0
- package/dist/i18n/rtl.d.ts +27 -0
- package/dist/i18n/rtl.d.ts.map +1 -0
- package/dist/i18n/rtl.js +47 -0
- package/dist/i18n/rtl.js.map +1 -0
- package/dist/i18n/server-messages.d.ts +56 -0
- package/dist/i18n/server-messages.d.ts.map +1 -0
- package/dist/i18n/server-messages.js +163 -0
- package/dist/i18n/server-messages.js.map +1 -0
- package/dist/i18n/templates.d.ts +5 -0
- package/dist/i18n/templates.d.ts.map +1 -1
- package/dist/i18n/templates.js +5 -0
- package/dist/i18n/templates.js.map +1 -1
- package/dist/i18n/ui.d.ts +85 -0
- package/dist/i18n/ui.d.ts.map +1 -0
- package/dist/i18n/ui.js +151 -0
- package/dist/i18n/ui.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/schemas/capture.d.ts +8 -0
- package/dist/schemas/capture.d.ts.map +1 -1
- package/dist/schemas/capture.js +6 -0
- package/dist/schemas/capture.js.map +1 -1
- package/dist/schemas/enums.d.ts +2 -0
- package/dist/schemas/enums.d.ts.map +1 -1
- package/package.json +8 -3
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TW = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Traditional Chinese — the thirteenth launch language (2026-10-21).
|
|
6
|
+
*
|
|
7
|
+
* Written for Taiwan usage rather than transliterated from `zh-CN`: a calendar is a 日曆,
|
|
8
|
+
* settings are 設定, signing in is 登入, an event is an 活動 (Google Calendar's own term in
|
|
9
|
+
* this locale), a reminder channel is a 管道, and the privacy policy is 隱私權政策. Character
|
|
10
|
+
* conversion alone would have produced text that is readable but foreign to a Taiwanese
|
|
11
|
+
* reader — the same reason `pt-BR` is not `pt-PT` with different spelling.
|
|
12
|
+
*
|
|
13
|
+
* The sentence shapes stay as terse as the Simplified table: these two are the same product
|
|
14
|
+
* in the same language family, and a member switching script should not get longer screens.
|
|
15
|
+
*/
|
|
16
|
+
// `EN` is a value import on purpose: a handful of keys are *by design* the same in
|
|
17
|
+
// every language (brand names, the example invite code, the developer diagnostic —
|
|
18
|
+
// see `UNTRANSLATED_BY_DESIGN`), and borrowing the English string is how that stays
|
|
19
|
+
// one decision instead of thirteen copies that can drift apart.
|
|
20
|
+
const en_US_1 = require("./en-US");
|
|
21
|
+
exports.TW = {
|
|
22
|
+
"common.next": "下一步",
|
|
23
|
+
"common.back": "返回",
|
|
24
|
+
"common.tryAgain": "重試",
|
|
25
|
+
"common.dismiss": "關閉",
|
|
26
|
+
"common.none": "無",
|
|
27
|
+
"login.subtitle": "你的語音日曆助理",
|
|
28
|
+
"login.continueWithGoogle": "使用 Google 繼續",
|
|
29
|
+
"login.signingIn": "登入中…",
|
|
30
|
+
"login.failed": "Google 登入失敗",
|
|
31
|
+
"login.configWarning": en_US_1.EN["login.configWarning"],
|
|
32
|
+
"setup.titleGroup": "設定你的群組",
|
|
33
|
+
"setup.titleSolo": "設定你的日曆",
|
|
34
|
+
"setup.justForMe": "只給自己用",
|
|
35
|
+
"setup.createOrJoin": "建立或加入群組",
|
|
36
|
+
"setup.yourName": "你的名字",
|
|
37
|
+
"setup.namePlaceholder": "例如:媽媽",
|
|
38
|
+
"setup.groupName": "群組名稱",
|
|
39
|
+
"setup.calendarName": "日曆名稱",
|
|
40
|
+
"setup.soloNamePlaceholder": "我的日曆",
|
|
41
|
+
"setup.groupNamePlaceholder": "例如:王家",
|
|
42
|
+
"setup.soloHint": "單人模式會把活動寫進你自己的 Google 日曆。",
|
|
43
|
+
"setup.inviteQuestion": "有邀請碼嗎?",
|
|
44
|
+
"setup.invitePlaceholder": en_US_1.EN["setup.invitePlaceholder"],
|
|
45
|
+
"setup.joinWithCode": "用邀請碼加入",
|
|
46
|
+
"setup.languageQuestion": "你會說哪種語言?",
|
|
47
|
+
"setup.languageFootnote": "語音辨識、提醒和介面都會用它。",
|
|
48
|
+
"setup.voiceQuestion": "想讓哪個聲音讀給你聽?",
|
|
49
|
+
"setup.voiceFootnote": "隨時可以在設定裡更改。",
|
|
50
|
+
"setup.styleQuestion": "助手該怎麼跟你說話?",
|
|
51
|
+
"setup.styleFootnote": "決定它每次為你朗讀確認時的語氣。",
|
|
52
|
+
"setup.avatarQuestion": "選擇你的頭像",
|
|
53
|
+
"setup.avatarFootnote": "頭像是你在活動和提醒上的標記 —— 與助手的聲音無關。",
|
|
54
|
+
"setup.createGroup": "建立我的群組",
|
|
55
|
+
"setup.createCalendar": "建立我的日曆",
|
|
56
|
+
"setup.startOver": "重新開始",
|
|
57
|
+
"setup.settingUpGroup": "正在設定你的群組…",
|
|
58
|
+
"setup.settingUpCalendar": "正在設定你的日曆…",
|
|
59
|
+
"setup.errorCreateGroup": "無法建立群組",
|
|
60
|
+
"setup.errorCreateCalendar": "無法建立你的日曆",
|
|
61
|
+
"setup.errorJoin": "無法加入群組",
|
|
62
|
+
"today.title": "今天",
|
|
63
|
+
"today.welcome": "你好,{name}",
|
|
64
|
+
"today.group": "群組:{name}",
|
|
65
|
+
"today.placeholder": "很快你只要說一句就能新增活動。在那之前,這一頁先佔個位。",
|
|
66
|
+
"capture.title": "記錄",
|
|
67
|
+
"capture.holdToTalk": "按住說話",
|
|
68
|
+
"capture.listening": "正在聽… {time}",
|
|
69
|
+
"capture.sending": "傳送中…",
|
|
70
|
+
"capture.working": "正在理解你說的話…",
|
|
71
|
+
"capture.orType": "或打字輸入",
|
|
72
|
+
"capture.placeholder": "下週二下午三點,市中心牙科診所回診",
|
|
73
|
+
"capture.send": "傳送",
|
|
74
|
+
"capture.emailHint": "也可以把郵件轉寄到 {email}。",
|
|
75
|
+
"capture.micPermission": "我需要麥克風才能聽見你。請到設定裡開啟,或在下面打字。",
|
|
76
|
+
"capture.recordFailed": "沒有錄到 —— 請再試一次。",
|
|
77
|
+
"capture.holdLonger": "按住按鈕再說話 —— 或在下面打字。",
|
|
78
|
+
"capture.doneConfirmed": "已加入你的日曆。",
|
|
79
|
+
"capture.doneDiscarded": "已捨棄。",
|
|
80
|
+
"card.playAgain": "再聽一遍",
|
|
81
|
+
"card.title": "標題",
|
|
82
|
+
"card.date": "日期",
|
|
83
|
+
"card.start": "開始",
|
|
84
|
+
"card.end": "結束",
|
|
85
|
+
"card.location": "地點",
|
|
86
|
+
"card.notes": "備註",
|
|
87
|
+
"card.allDay": "全天",
|
|
88
|
+
"card.today": "今天",
|
|
89
|
+
"card.tomorrow": "明天",
|
|
90
|
+
"card.discard": "捨棄",
|
|
91
|
+
"card.confirm": "確認",
|
|
92
|
+
"card.badTime": "請依照 15:00 或 3pm 這樣的格式填寫時間。",
|
|
93
|
+
"card.badDate": "請依照 2026-09-27 這樣的格式填寫日期。",
|
|
94
|
+
"card.badTitle": "替這個活動取個標題。",
|
|
95
|
+
"card.badTooLong": "太長了 —— 請縮短一些。",
|
|
96
|
+
"card.badField": "確認前請檢查這一項。",
|
|
97
|
+
"card.checkFields": "請檢查標黃的欄位。",
|
|
98
|
+
"card.voiceFallback": "你儲存的音色已無法使用 —— 這則由群組目前的音色朗讀。",
|
|
99
|
+
"card.checkVolume": "聽不到?請檢查音量。",
|
|
100
|
+
"settings.title": "設定",
|
|
101
|
+
"settings.yourName": "你的名字",
|
|
102
|
+
"settings.nameFootnote": "活動和提醒裡顯示的就是這個名字。",
|
|
103
|
+
"settings.saveName": "儲存名字",
|
|
104
|
+
"settings.language": "語言",
|
|
105
|
+
"settings.languageFootnote": "語音辨識、提醒和介面都用這種語言。",
|
|
106
|
+
"settings.voice": "你的音色",
|
|
107
|
+
"settings.voiceFootnote": "為你朗讀確認和提醒的聲音。",
|
|
108
|
+
"settings.style": "說話風格",
|
|
109
|
+
"settings.styleFootnote": "每次記錄後你聽到的確認語音的語氣。",
|
|
110
|
+
"settings.primaryChannel": "主要提醒管道",
|
|
111
|
+
"settings.primaryChannelFootnote": "提醒會先透過這個管道發送。",
|
|
112
|
+
"settings.fallbackChannel": "備用管道",
|
|
113
|
+
"settings.fallbackChannelFootnote": "只在主要管道失敗時使用(不會重複傳送)。",
|
|
114
|
+
"settings.fallbackAlreadyPrimary": "已是主要管道",
|
|
115
|
+
"settings.yourColor": "你的顏色",
|
|
116
|
+
"settings.currentColor": "目前:{color}",
|
|
117
|
+
"settings.colorNotAssigned": "未分配",
|
|
118
|
+
"settings.colorFootnoteGroup": "你建立的每個活動都會用這個顏色 —— 群組靠它分辨誰的活動。其他成員已在使用的顏色不能選。",
|
|
119
|
+
"settings.colorFootnoteSolo": "你建立的每個活動都會用這個顏色。",
|
|
120
|
+
"settings.yourAvatar": "你的頭像",
|
|
121
|
+
"settings.avatarFootnote": "標記你的活動、確認和提醒。",
|
|
122
|
+
"settings.saveLabelName": "你的名字",
|
|
123
|
+
"settings.saveLabelLanguage": "語言",
|
|
124
|
+
"settings.saveLabelVoice": "音色",
|
|
125
|
+
"settings.saveLabelStyle": "說話風格",
|
|
126
|
+
"settings.saveLabelChannels": "提醒管道",
|
|
127
|
+
"settings.saveLabelColor": "顏色",
|
|
128
|
+
"settings.saveLabelAvatar": "頭像",
|
|
129
|
+
"settings.saving": "正在儲存{label}…",
|
|
130
|
+
"settings.signedInAs": "已登入:{email}",
|
|
131
|
+
"settings.signOut": "登出",
|
|
132
|
+
"settings.privacyPolicy": "隱私權政策",
|
|
133
|
+
"settings.privacyPolicyHint": "將在瀏覽器中開啟{url}。",
|
|
134
|
+
"settings.privacyPolicyError": "無法開啟隱私權政策。",
|
|
135
|
+
"settings.errorLoad": "無法載入你的設定",
|
|
136
|
+
"settings.errorSave": "無法儲存{label}",
|
|
137
|
+
"settings.profileIncomplete": "這份個人檔案缺少一些欄位 —— 先顯示預設值。",
|
|
138
|
+
"voices.loading": "正在載入音色清單…",
|
|
139
|
+
"voices.loadError": "無法載入音色清單",
|
|
140
|
+
"voices.playError": "無法播放試聽",
|
|
141
|
+
"voices.preparing": "正在準備試聽…",
|
|
142
|
+
"voices.hearSample": "試聽{voice}",
|
|
143
|
+
"voices.previewHint": "用你的語言說一句短句,由這個音色朗讀。",
|
|
144
|
+
"style.professional": "專業",
|
|
145
|
+
"style.warm_casual": "溫暖隨和",
|
|
146
|
+
"style.friendly_brief": "友善簡潔",
|
|
147
|
+
"channel.sms": en_US_1.EN["channel.sms"],
|
|
148
|
+
"channel.whatsapp": en_US_1.EN["channel.whatsapp"],
|
|
149
|
+
"channel.telegram": en_US_1.EN["channel.telegram"],
|
|
150
|
+
"color.1": "薰衣草 — 淺紫藍",
|
|
151
|
+
"color.2": "鼠尾草 — 淺綠",
|
|
152
|
+
"color.3": "葡萄 — 紫",
|
|
153
|
+
"color.4": "火烈鳥 — 珊瑚粉",
|
|
154
|
+
"color.5": "香蕉 — 黃",
|
|
155
|
+
"color.6": "橘子 — 橙",
|
|
156
|
+
"color.7": "孔雀 — 湖藍",
|
|
157
|
+
"color.8": "石墨 — 灰",
|
|
158
|
+
"color.9": "藍莓 — 藍",
|
|
159
|
+
"color.10": "羅勒 — 深綠",
|
|
160
|
+
"color.11": "番茄 — 紅",
|
|
161
|
+
"avatar.mom_01": "媽媽",
|
|
162
|
+
"avatar.mom_02": "媽媽(紅髮)",
|
|
163
|
+
"avatar.dad_01": "爸爸",
|
|
164
|
+
"avatar.dad_02": "爸爸(捲髮)",
|
|
165
|
+
"avatar.kid_01": "孩子",
|
|
166
|
+
"avatar.kid_02": "女孩",
|
|
167
|
+
"avatar.kid_03": "男孩",
|
|
168
|
+
"avatar.professional_f_01": "職業女性",
|
|
169
|
+
"avatar.professional_m_01": "職業男性",
|
|
170
|
+
"avatar.professional_x_01": "職場人士",
|
|
171
|
+
"avatar.grandparent_f_01": "奶奶/外婆",
|
|
172
|
+
"avatar.grandparent_m_01": "爺爺/外公",
|
|
173
|
+
"avatar.generic_01": "中性",
|
|
174
|
+
"avatar.generic_02": "普通人",
|
|
175
|
+
"avatar.generic_03": "匿名",
|
|
176
|
+
"error.connection": "連線中斷了 —— 請再試一次。",
|
|
177
|
+
"error.notAnEvent": "我沒能把它變成活動 —— 請換個說法。",
|
|
178
|
+
"error.tooLong": "有點長了 —— 請只留一個行程。",
|
|
179
|
+
"error.recordingGone": "這段錄音已經不在了 —— 請重新錄一次。",
|
|
180
|
+
"error.noAudio": "這段錄音裡我沒聽到任何聲音 —— 請再試一次。",
|
|
181
|
+
"error.badDateTime": "這個日期時間我沒讀懂 —— 請檢查一下。",
|
|
182
|
+
"error.colorTaken": "群組裡已經有成員在使用這個顏色了。",
|
|
183
|
+
"error.groupNotJoinable": "這個群組用的是群主的個人日曆,無法接受成員。",
|
|
184
|
+
"error.noGoogleEmail": "你的帳戶沒有 Google 電子郵件 —— 請用 Google 登入後再加入群組。",
|
|
185
|
+
"error.noEvent": "這則記事裡我找不到活動 —— 請再試一次。",
|
|
186
|
+
"error.noteGone": "這則記事已經不在了。",
|
|
187
|
+
"error.notYours": "這則記事不屬於你。",
|
|
188
|
+
"error.badDecision": "儲存這個決定時出錯了 —— 請再試一次。",
|
|
189
|
+
"error.calendarSave": "沒能將它加入你的日曆 —— 請再試一次。",
|
|
190
|
+
"error.signIn": "請重新登入。",
|
|
191
|
+
"error.profileMissing": "你的設定似乎不完整 —— 請重新登入。",
|
|
192
|
+
"error.invalidInvite": "這個邀請碼無效。",
|
|
193
|
+
"error.alreadySetUp": "你已經設定過日曆了。",
|
|
194
|
+
"error.generic": "出了點問題 —— 請再試一次。",
|
|
195
|
+
};
|
|
196
|
+
//# sourceMappingURL=zh-TW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zh-TW.js","sourceRoot":"","sources":["../../../src/i18n/copy/zh-TW.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text direction (Milestone 1.9.7, batch 3) — which way each launch language reads, as an
|
|
3
|
+
* **exhaustive map** rather than a list of exceptions.
|
|
4
|
+
*
|
|
5
|
+
* `Record<Language, TextDirection>` is the whole point: a thirteenth language added to
|
|
6
|
+
* `SUPPORTED_LANGUAGES` fails this file's typecheck until someone says which way it reads —
|
|
7
|
+
* the same rule the copy tables enforce with `Record<UiKey, string>`. You cannot add a
|
|
8
|
+
* language to this product by forgetting part of it.
|
|
9
|
+
*
|
|
10
|
+
* What this decides is layout mirroring only: the `direction` style in `app/App.tsx` (and the
|
|
11
|
+
* paragraph alignment in `app/src/components/Text.tsx`, which cannot inherit direction the way
|
|
12
|
+
* layout does). What a language *says* is `./ui.ts`; the two are deliberately separate files
|
|
13
|
+
* because they answer different questions and are reviewed by different eyes.
|
|
14
|
+
*/
|
|
15
|
+
import { type Language } from "./ui";
|
|
16
|
+
export type TextDirection = "ltr" | "rtl";
|
|
17
|
+
export declare const TEXT_DIRECTION: Record<Language, TextDirection>;
|
|
18
|
+
/**
|
|
19
|
+
* Whether a language tag reads right-to-left.
|
|
20
|
+
*
|
|
21
|
+
* Resolves exactly the way the copy table does — exact tag → base language → nothing — so
|
|
22
|
+
* `ar-EG` lands on `ar-SA` and mirrors, the same fallback that gives an `ar-EG` member
|
|
23
|
+
* Arabic copy. A tag we do not ship at all renders in English, and English reads left to
|
|
24
|
+
* right, so `false` is the honest answer rather than a guess.
|
|
25
|
+
*/
|
|
26
|
+
export declare function isRtlLanguage(language: string | null | undefined): boolean;
|
|
27
|
+
//# sourceMappingURL=rtl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rtl.d.ts","sourceRoot":"","sources":["../../src/i18n/rtl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAqB,KAAK,QAAQ,EAAE,MAAM,MAAM,CAAC;AAExD,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,KAAK,CAAC;AAE1C,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,QAAQ,EAAE,aAAa,CAc1D,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAG1E"}
|
package/dist/i18n/rtl.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TEXT_DIRECTION = void 0;
|
|
4
|
+
exports.isRtlLanguage = isRtlLanguage;
|
|
5
|
+
/**
|
|
6
|
+
* Text direction (Milestone 1.9.7, batch 3) — which way each launch language reads, as an
|
|
7
|
+
* **exhaustive map** rather than a list of exceptions.
|
|
8
|
+
*
|
|
9
|
+
* `Record<Language, TextDirection>` is the whole point: a thirteenth language added to
|
|
10
|
+
* `SUPPORTED_LANGUAGES` fails this file's typecheck until someone says which way it reads —
|
|
11
|
+
* the same rule the copy tables enforce with `Record<UiKey, string>`. You cannot add a
|
|
12
|
+
* language to this product by forgetting part of it.
|
|
13
|
+
*
|
|
14
|
+
* What this decides is layout mirroring only: the `direction` style in `app/App.tsx` (and the
|
|
15
|
+
* paragraph alignment in `app/src/components/Text.tsx`, which cannot inherit direction the way
|
|
16
|
+
* layout does). What a language *says* is `./ui.ts`; the two are deliberately separate files
|
|
17
|
+
* because they answer different questions and are reviewed by different eyes.
|
|
18
|
+
*/
|
|
19
|
+
const ui_1 = require("./ui");
|
|
20
|
+
exports.TEXT_DIRECTION = {
|
|
21
|
+
"en-US": "ltr",
|
|
22
|
+
"zh-CN": "ltr",
|
|
23
|
+
"zh-TW": "ltr",
|
|
24
|
+
"es-MX": "ltr",
|
|
25
|
+
"fr-FR": "ltr",
|
|
26
|
+
"de-DE": "ltr",
|
|
27
|
+
"pt-BR": "ltr",
|
|
28
|
+
"ru-RU": "ltr",
|
|
29
|
+
"ar-SA": "rtl",
|
|
30
|
+
"hi-IN": "ltr",
|
|
31
|
+
"he-IL": "rtl",
|
|
32
|
+
"ja-JP": "ltr",
|
|
33
|
+
"ko-KR": "ltr",
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Whether a language tag reads right-to-left.
|
|
37
|
+
*
|
|
38
|
+
* Resolves exactly the way the copy table does — exact tag → base language → nothing — so
|
|
39
|
+
* `ar-EG` lands on `ar-SA` and mirrors, the same fallback that gives an `ar-EG` member
|
|
40
|
+
* Arabic copy. A tag we do not ship at all renders in English, and English reads left to
|
|
41
|
+
* right, so `false` is the honest answer rather than a guess.
|
|
42
|
+
*/
|
|
43
|
+
function isRtlLanguage(language) {
|
|
44
|
+
const resolved = (0, ui_1.resolveUiLanguage)(language);
|
|
45
|
+
return resolved ? exports.TEXT_DIRECTION[resolved] === "rtl" : false;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=rtl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rtl.js","sourceRoot":"","sources":["../../src/i18n/rtl.ts"],"names":[],"mappings":";;;AA0CA,sCAGC;AA7CD;;;;;;;;;;;;;GAaG;AACH,6BAAwD;AAI3C,QAAA,cAAc,GAAoC;IAC7D,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,KAAK;CACf,CAAC;AAEF;;;;;;;GAOG;AACH,SAAgB,aAAa,CAAC,QAAmC;IAC/D,MAAM,QAAQ,GAAG,IAAA,sBAAiB,EAAC,QAAQ,CAAC,CAAC;IAC7C,OAAO,QAAQ,CAAC,CAAC,CAAC,sBAAc,CAAC,QAAQ,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AAC/D,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The server's sentences, in the member's language (Milestone 1.9.7).
|
|
3
|
+
*
|
|
4
|
+
* Every callable in `functions/src` refuses with an `HttpsError`, and those sentences were
|
|
5
|
+
* written for the member — `That note is no longer there`, `I could not hear anything in
|
|
6
|
+
* that recording`. The app renders them directly (`captureErrorMessage`), which was right
|
|
7
|
+
* while the interface was English: the sentence and the screen spoke the same language.
|
|
8
|
+
* M1.9.7 breaks that coincidence, and this file is how it is repaired.
|
|
9
|
+
*
|
|
10
|
+
* Two rules, and one deliberate limitation:
|
|
11
|
+
*
|
|
12
|
+
* 1. **The key is the exact message text.** We own these strings; the guard test
|
|
13
|
+
* (`tests/functions/i18n-messages.test.js`) scans `functions/src` for every literal
|
|
14
|
+
* `HttpsError` message and fails when one is neither mapped here nor marked internal.
|
|
15
|
+
* That is the point: the mapping can only stay correct if something breaks when the
|
|
16
|
+
* sentence changes. (A template-literal message is out of the scan's reach and lands
|
|
17
|
+
* on the generic sentence — a gap worth knowing about, not worth closing by regex.)
|
|
18
|
+
*
|
|
19
|
+
* "Exact" needs one caveat, and it hid every refusal behind the generic sentence until it
|
|
20
|
+
* was found (2026-10-01): the client never receives a byte-identical sentence.
|
|
21
|
+
* `@firebase/functions` builds its error as `` `${message} [${httpStatus}]` ``, so the
|
|
22
|
+
* status travels welded to the sentence and *every* lookup in the table missed — a
|
|
23
|
+
* refused `createCircle` read as the generic "could not create your calendar" instead of
|
|
24
|
+
* "please sign in again". The guard test below cannot see this: the mangling happens in
|
|
25
|
+
* the SDK, outside the source it scans. So the lookup strips the suffix first
|
|
26
|
+
* (`stripHttpStatus`), and `server-messages.test.ts` pins the behaviour.
|
|
27
|
+
* 2. **`null` means "never show this to a member."** Internal faults — a schema that
|
|
28
|
+
* failed validation, a stack-trace-shaped message — get `error.generic` instead of a
|
|
29
|
+
* translation, because a member cannot act on them and the wording may leak internals.
|
|
30
|
+
* 3. **Unmapped messages also get `error.generic`, never the raw English.** A member
|
|
31
|
+
* should not read prose in a language they did not choose *because something failed*.
|
|
32
|
+
* `localizeServerMessage` reports whether it fell back, so the caller can log the
|
|
33
|
+
* original for the console — where it belongs.
|
|
34
|
+
*/
|
|
35
|
+
import { type Language, type UiParams } from "./ui";
|
|
36
|
+
export interface LocalizedServerMessage {
|
|
37
|
+
/** What the member reads — never English prose. */
|
|
38
|
+
text: string;
|
|
39
|
+
/** False when no mapping matched, i.e. the sentence above is the generic one. */
|
|
40
|
+
mapped: boolean;
|
|
41
|
+
}
|
|
42
|
+
/** A server sentence as the client receives it, i.e. without the SDK's ` [400]` tail. */
|
|
43
|
+
export declare function stripHttpStatus(message: string): string;
|
|
44
|
+
/** The sentence a member reads for a server refusal. */
|
|
45
|
+
export declare function localizeServerMessage(language: Language | string | null | undefined, message: string, params?: UiParams): LocalizedServerMessage;
|
|
46
|
+
/** True when this exact server sentence is known to be safe to show a member. */
|
|
47
|
+
export declare function isMappedServerMessage(message: string): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Every sentence this file has an opinion about — mapped or marked internal. Exported for
|
|
50
|
+
* the guard test in `tests/functions/i18n-messages.test.js`, which scans `functions/src`
|
|
51
|
+
* for literal `HttpsError` messages and fails when one is not in this list. That test is
|
|
52
|
+
* the whole reason the mapping can be trusted: without it, renaming a server sentence
|
|
53
|
+
* would silently downgrade a member's message to the generic one.
|
|
54
|
+
*/
|
|
55
|
+
export declare const KNOWN_SERVER_MESSAGES: readonly string[];
|
|
56
|
+
//# sourceMappingURL=server-messages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-messages.d.ts","sourceRoot":"","sources":["../../src/i18n/server-messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,EAAa,KAAK,QAAQ,EAAc,KAAK,QAAQ,EAAE,MAAM,MAAM,CAAC;AA8F3E,MAAM,WAAW,sBAAsB;IACrC,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,MAAM,EAAE,OAAO,CAAC;CACjB;AAgBD,yFAAyF;AACzF,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wDAAwD;AACxD,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,EAC9C,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,QAAQ,GAChB,sBAAsB,CAQxB;AAED,iFAAiF;AACjF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAElD,CAAC"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KNOWN_SERVER_MESSAGES = void 0;
|
|
4
|
+
exports.stripHttpStatus = stripHttpStatus;
|
|
5
|
+
exports.localizeServerMessage = localizeServerMessage;
|
|
6
|
+
exports.isMappedServerMessage = isMappedServerMessage;
|
|
7
|
+
/**
|
|
8
|
+
* The server's sentences, in the member's language (Milestone 1.9.7).
|
|
9
|
+
*
|
|
10
|
+
* Every callable in `functions/src` refuses with an `HttpsError`, and those sentences were
|
|
11
|
+
* written for the member — `That note is no longer there`, `I could not hear anything in
|
|
12
|
+
* that recording`. The app renders them directly (`captureErrorMessage`), which was right
|
|
13
|
+
* while the interface was English: the sentence and the screen spoke the same language.
|
|
14
|
+
* M1.9.7 breaks that coincidence, and this file is how it is repaired.
|
|
15
|
+
*
|
|
16
|
+
* Two rules, and one deliberate limitation:
|
|
17
|
+
*
|
|
18
|
+
* 1. **The key is the exact message text.** We own these strings; the guard test
|
|
19
|
+
* (`tests/functions/i18n-messages.test.js`) scans `functions/src` for every literal
|
|
20
|
+
* `HttpsError` message and fails when one is neither mapped here nor marked internal.
|
|
21
|
+
* That is the point: the mapping can only stay correct if something breaks when the
|
|
22
|
+
* sentence changes. (A template-literal message is out of the scan's reach and lands
|
|
23
|
+
* on the generic sentence — a gap worth knowing about, not worth closing by regex.)
|
|
24
|
+
*
|
|
25
|
+
* "Exact" needs one caveat, and it hid every refusal behind the generic sentence until it
|
|
26
|
+
* was found (2026-10-01): the client never receives a byte-identical sentence.
|
|
27
|
+
* `@firebase/functions` builds its error as `` `${message} [${httpStatus}]` ``, so the
|
|
28
|
+
* status travels welded to the sentence and *every* lookup in the table missed — a
|
|
29
|
+
* refused `createCircle` read as the generic "could not create your calendar" instead of
|
|
30
|
+
* "please sign in again". The guard test below cannot see this: the mangling happens in
|
|
31
|
+
* the SDK, outside the source it scans. So the lookup strips the suffix first
|
|
32
|
+
* (`stripHttpStatus`), and `server-messages.test.ts` pins the behaviour.
|
|
33
|
+
* 2. **`null` means "never show this to a member."** Internal faults — a schema that
|
|
34
|
+
* failed validation, a stack-trace-shaped message — get `error.generic` instead of a
|
|
35
|
+
* translation, because a member cannot act on them and the wording may leak internals.
|
|
36
|
+
* 3. **Unmapped messages also get `error.generic`, never the raw English.** A member
|
|
37
|
+
* should not read prose in a language they did not choose *because something failed*.
|
|
38
|
+
* `localizeServerMessage` reports whether it fell back, so the caller can log the
|
|
39
|
+
* original for the console — where it belongs.
|
|
40
|
+
*/
|
|
41
|
+
const ui_1 = require("./ui");
|
|
42
|
+
/** Map a server sentence to a copy key, or to `null` when a member must not see it. */
|
|
43
|
+
const SERVER_MESSAGES = {
|
|
44
|
+
// ── Network / provider faults: the member can retry ───────────────────────
|
|
45
|
+
"Could not reach the Google Calendar API": "error.connection",
|
|
46
|
+
"Could not reach the Google OAuth token endpoint": "error.connection",
|
|
47
|
+
"Could not reach the extraction model": "error.connection",
|
|
48
|
+
"Could not reach the transcription service": "error.connection",
|
|
49
|
+
"Could not reach the voice provider": "error.connection",
|
|
50
|
+
"The transcription service rejected the key — check ASR_API_KEY in the server environment.": null,
|
|
51
|
+
"The extraction model rejected the key — check LLM_API_KEY in the server environment.": null,
|
|
52
|
+
"The voice provider rejected the key — check TTS_API_KEY in the server environment.": null,
|
|
53
|
+
"Voice playback is not configured (TTS_API_KEY is unset)": null,
|
|
54
|
+
"TOKEN_ENCRYPTION_KEY is not configured on the server (see .env.example).": null,
|
|
55
|
+
"GOOGLE_OAUTH_CLIENT_ID is not configured on the server.": null,
|
|
56
|
+
// ── Capture: the recording itself ─────────────────────────────────────────
|
|
57
|
+
"I could not hear anything in that recording": "error.noAudio",
|
|
58
|
+
"The uploaded recording is empty": "error.noAudio",
|
|
59
|
+
"That recording is too long — please keep it short": "error.tooLong",
|
|
60
|
+
"The recording is too large to transcribe": "error.tooLong",
|
|
61
|
+
"That recording is no longer there — please record again": "error.recordingGone",
|
|
62
|
+
"That recording does not belong to you": "error.notYours",
|
|
63
|
+
"Invalid recording path": "error.notYours",
|
|
64
|
+
// ── Capture: the note and its decision ────────────────────────────────────
|
|
65
|
+
"There was nothing to extract": "error.notAnEvent",
|
|
66
|
+
"There is nothing to read back": "error.notAnEvent",
|
|
67
|
+
"The extraction model returned an empty answer": "error.notAnEvent",
|
|
68
|
+
"That is not a capture decision": "error.badDecision",
|
|
69
|
+
"That date and time could not be read — please check them": "error.badDateTime",
|
|
70
|
+
"That note is no longer there": "error.noteGone",
|
|
71
|
+
"That note has no event to confirm": "error.noEvent",
|
|
72
|
+
"That note belongs to someone else": "error.notYours",
|
|
73
|
+
// ── Calendar write (M1.6's confirmEvent) ──────────────────────────────────
|
|
74
|
+
"That note has not been confirmed yet": null,
|
|
75
|
+
"Google Calendar would not accept the event": "error.calendarSave",
|
|
76
|
+
"Google Calendar did not return the saved event": null,
|
|
77
|
+
"Google would not renew the calendar connection": "error.signIn",
|
|
78
|
+
"The circle's calendar could not be read": null,
|
|
79
|
+
"Invalid confirm payload": null,
|
|
80
|
+
// ── Setup, membership, sign-in ────────────────────────────────────────────
|
|
81
|
+
"Invalid invite code": "error.invalidInvite",
|
|
82
|
+
"You've already completed setup": "error.alreadySetUp",
|
|
83
|
+
"Member doc is missing — re-run setup": "error.profileMissing",
|
|
84
|
+
"Your member profile could not be read": "error.profileMissing",
|
|
85
|
+
"Finish setting up your calendar before capturing an event": "error.profileMissing",
|
|
86
|
+
"Finish setting up your calendar before confirming an event": "error.profileMissing",
|
|
87
|
+
"No setup on file — finish setting up before editing settings": "error.profileMissing",
|
|
88
|
+
"Sign in with Firebase first (native Google Sign-In → idToken → signInWithCredential)": "error.signIn",
|
|
89
|
+
"No Google authorization on file — the client must complete exchangeGoogleCode first": "error.signIn",
|
|
90
|
+
"This group uses the owner's personal calendar and cannot accept members": "error.groupNotJoinable",
|
|
91
|
+
"Your Firebase account has no Google email — sign in with Google to join a group": "error.noGoogleEmail",
|
|
92
|
+
"Another member of your group is already using that color": "error.colorTaken",
|
|
93
|
+
"I could not turn that note into an event — please try rephrasing it": "error.notAnEvent",
|
|
94
|
+
"Please sign in first": "error.signIn",
|
|
95
|
+
"Sign in before capturing an event": "error.signIn",
|
|
96
|
+
"Sign in before changing settings": "error.signIn",
|
|
97
|
+
"Sign in before choosing a voice": "error.signIn",
|
|
98
|
+
"Sign in before confirming an event": "error.signIn",
|
|
99
|
+
"Sign in before hearing a voice": "error.signIn",
|
|
100
|
+
"Sign in before joining a group": "error.signIn",
|
|
101
|
+
// ── Internal: a member can do nothing with these, and they name internals ──
|
|
102
|
+
"Calendar API returned no calendar id": null,
|
|
103
|
+
"Invalid event draft": null,
|
|
104
|
+
"Invalid join payload": null,
|
|
105
|
+
"Invalid listEvents payload": null,
|
|
106
|
+
"Invalid preview request": null,
|
|
107
|
+
"Invalid settings payload": null,
|
|
108
|
+
"Invalid setup payload": null,
|
|
109
|
+
"Invalid updateEvent payload": null,
|
|
110
|
+
"Invalid voice request": null,
|
|
111
|
+
"Stored token payload has an unexpected format": null,
|
|
112
|
+
"That note could not be read": null,
|
|
113
|
+
"This group has no recorded owner": null,
|
|
114
|
+
"Send either a recording path (storagePath: audio/<uid>/...) or text": null,
|
|
115
|
+
"Transcription is not configured (ASR_API_KEY is unset)": null,
|
|
116
|
+
"Event extraction is not configured (LLM_API_KEY is unset)": null,
|
|
117
|
+
"capture doc failed schema validation": null,
|
|
118
|
+
"authorizationCode is required": null,
|
|
119
|
+
"Google did not return a refresh token. Ensure the native SDK is configured ": null,
|
|
120
|
+
"googleEventId is required": null,
|
|
121
|
+
"Invalid rescheduleOrCancelEvent payload": null,
|
|
122
|
+
"oneTimeCode must be 6 characters": null,
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* The HTTP status the JavaScript SDK welds onto a callable's sentence.
|
|
126
|
+
*
|
|
127
|
+
* `@firebase/functions` builds its error as `` `${description} [${httpStatus}]` ``
|
|
128
|
+
* (`codeForResponse` in its dist), so a member's client sees
|
|
129
|
+
* `"Please sign in first [401]"`, never `"Please sign in first"`. Since the table above keys
|
|
130
|
+
* the exact sentence — deliberately, so the guard test can hold it to the backend's source —
|
|
131
|
+
* the suffix has to come off before the lookup, or nothing ever matches.
|
|
132
|
+
*
|
|
133
|
+
* Only the SDK's own shape is removed: three digits in brackets, at the end. A sentence that
|
|
134
|
+
* happens to contain brackets elsewhere is left exactly as it is.
|
|
135
|
+
*/
|
|
136
|
+
const TRAILING_HTTP_STATUS = / \[\d{3}\]$/;
|
|
137
|
+
/** A server sentence as the client receives it, i.e. without the SDK's ` [400]` tail. */
|
|
138
|
+
function stripHttpStatus(message) {
|
|
139
|
+
return message.replace(TRAILING_HTTP_STATUS, "");
|
|
140
|
+
}
|
|
141
|
+
/** The sentence a member reads for a server refusal. */
|
|
142
|
+
function localizeServerMessage(language, message, params) {
|
|
143
|
+
const key = SERVER_MESSAGES[stripHttpStatus(message)];
|
|
144
|
+
// An unmapped sentence and one we marked internal land in the same place — the
|
|
145
|
+
// difference is only that one of them was a decision.
|
|
146
|
+
if (typeof key !== "string") {
|
|
147
|
+
return { text: (0, ui_1.translate)(language, "error.generic", params), mapped: false };
|
|
148
|
+
}
|
|
149
|
+
return { text: (0, ui_1.translate)(language, key, params), mapped: true };
|
|
150
|
+
}
|
|
151
|
+
/** True when this exact server sentence is known to be safe to show a member. */
|
|
152
|
+
function isMappedServerMessage(message) {
|
|
153
|
+
return typeof SERVER_MESSAGES[stripHttpStatus(message)] === "string";
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Every sentence this file has an opinion about — mapped or marked internal. Exported for
|
|
157
|
+
* the guard test in `tests/functions/i18n-messages.test.js`, which scans `functions/src`
|
|
158
|
+
* for literal `HttpsError` messages and fails when one is not in this list. That test is
|
|
159
|
+
* the whole reason the mapping can be trusted: without it, renaming a server sentence
|
|
160
|
+
* would silently downgrade a member's message to the generic one.
|
|
161
|
+
*/
|
|
162
|
+
exports.KNOWN_SERVER_MESSAGES = Object.freeze(Object.keys(SERVER_MESSAGES).sort());
|
|
163
|
+
//# sourceMappingURL=server-messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-messages.js","sourceRoot":"","sources":["../../src/i18n/server-messages.ts"],"names":[],"mappings":"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"}
|
package/dist/i18n/templates.d.ts
CHANGED
|
@@ -37,6 +37,11 @@ declare const COPY: {
|
|
|
37
37
|
readonly join: ",";
|
|
38
38
|
readonly location: "(📍 {location})";
|
|
39
39
|
};
|
|
40
|
+
readonly "zh-TW": {
|
|
41
|
+
readonly lead: "⏰ 提醒:";
|
|
42
|
+
readonly join: ",";
|
|
43
|
+
readonly location: "(📍 {location})";
|
|
44
|
+
};
|
|
40
45
|
readonly "es-MX": {
|
|
41
46
|
readonly lead: "⏰ Recordatorio: ";
|
|
42
47
|
readonly join: " — ";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/i18n/templates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,qBAAqB;IACpC,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;;;;;;;;;GAcG;AACH,QAAA,MAAM,IAAI
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/i18n/templates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,qBAAqB;IACpC,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;;;;;;;;;GAcG;AACH,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuB2E,CAAC;AAEtF,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,IAAI,CAAC;AAE5C;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAQhE;AAED,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB,GAAG,MAAM,CAI5F"}
|
package/dist/i18n/templates.js
CHANGED
|
@@ -25,6 +25,11 @@ exports.buildReminderMessage = buildReminderMessage;
|
|
|
25
25
|
const COPY = {
|
|
26
26
|
"en-US": { lead: "⏰ Reminder: ", join: " — ", location: " (📍 {location})" },
|
|
27
27
|
"zh-CN": { lead: "⏰ 提醒:", join: ",", location: "(📍 {location})" },
|
|
28
|
+
// Identical characters to zh-CN by necessity: the skeleton is 提醒 + full-width punctuation,
|
|
29
|
+
// and none of it differs between the two scripts. The row exists anyway because
|
|
30
|
+
// `templates.test.ts` requires every launch language to resolve to *itself* — otherwise a
|
|
31
|
+
// future zh-CN edit would silently rewrite zh-TW reminders too.
|
|
32
|
+
"zh-TW": { lead: "⏰ 提醒:", join: ",", location: "(📍 {location})" },
|
|
28
33
|
"es-MX": { lead: "⏰ Recordatorio: ", join: " — ", location: " (📍 {location})" },
|
|
29
34
|
// French puts a space before the colon — `Rappel :` — not `Rappel:`.
|
|
30
35
|
"fr-FR": { lead: "⏰ Rappel : ", join: " — ", location: " (📍 {location})" },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/i18n/templates.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/i18n/templates.ts"],"names":[],"mappings":"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"}
|