|
|
@@ -7,11 +7,12 @@ import {
|
|
7
|
7
|
type ReactNode,
|
|
8
|
8
|
} from 'react';
|
|
9
|
9
|
|
|
10
|
|
-type Language = 'en' | 'th';
|
|
|
10
|
+type Language = 'en' | 'th' | 'ja';
|
|
11
|
11
|
type Params = Record<string, string | number>;
|
|
12
|
12
|
|
|
13
|
13
|
const strings: Record<Language, Record<string, string>> = {
|
|
14
|
14
|
en: {
|
|
|
15
|
+ 'common.close': 'Close',
|
|
15
|
16
|
'tabs.home': 'Home',
|
|
16
|
17
|
'tabs.explore': 'Explore',
|
|
17
|
18
|
'tabs.onnx': 'Leaf Scan',
|
|
|
@@ -32,7 +33,7 @@ const strings: Record<Language, Record<string, string>> = {
|
|
32
|
33
|
'setup.noPhoto': 'No photo selected.',
|
|
33
|
34
|
'setup.uploadPhoto': 'Upload photo',
|
|
34
|
35
|
'setup.exportTitle': 'Export data',
|
|
35
|
|
- 'setup.exportHint': 'Download your local data as a CSV file.',
|
|
|
36
|
+ 'setup.exportHint': 'Download your local data as a JSON file.',
|
|
36
|
37
|
'setup.exportButton': 'Export data',
|
|
37
|
38
|
'setup.exported': 'Exported data.',
|
|
38
|
39
|
'setup.exportError': 'Export failed.',
|
|
|
@@ -44,6 +45,7 @@ const strings: Record<Language, Record<string, string>> = {
|
|
44
|
45
|
'setup.language': 'Language',
|
|
45
|
46
|
'setup.lang.en': 'English',
|
|
46
|
47
|
'setup.lang.th': 'Thai',
|
|
|
48
|
+ 'setup.lang.ja': 'Japanese',
|
|
47
|
49
|
'setup.currency': 'Default currency',
|
|
48
|
50
|
'setup.currencyPlaceholder': 'e.g. THB',
|
|
49
|
51
|
'setup.currency.thb': 'THB',
|
|
|
@@ -127,13 +129,20 @@ const strings: Record<Language, Record<string, string>> = {
|
|
127
|
129
|
'tasks.title': 'Daily Tasks',
|
|
128
|
130
|
'tasks.subtitle': 'Log today’s field routine.',
|
|
129
|
131
|
'tasks.loading': 'Loading tasks...',
|
|
|
132
|
+ 'tasks.saving': 'Saving...',
|
|
|
133
|
+ 'tasks.saved': 'Saved.',
|
|
130
|
134
|
'tasks.empty': 'No tasks configured yet.',
|
|
131
|
135
|
'tasks.pending': 'Pending',
|
|
132
|
136
|
'tasks.done': 'Done',
|
|
133
|
137
|
'tasks.complete': 'Mark done',
|
|
|
138
|
+ 'tasks.save': 'Save',
|
|
|
139
|
+ 'tasks.open': 'In progress',
|
|
134
|
140
|
'tasks.undo': 'Undo',
|
|
135
|
141
|
'tasks.notePlaceholder': 'Add notes for today...',
|
|
136
|
142
|
'tasks.photo': 'Task photo',
|
|
|
143
|
+ 'tasks.addMedia': 'Add media',
|
|
|
144
|
+ 'tasks.pickFromGallery': 'Pick from gallery',
|
|
|
145
|
+ 'tasks.takeMedia': 'Take photo / video',
|
|
137
|
146
|
'tasks.pickPhoto': 'Pick photo',
|
|
138
|
147
|
'tasks.takePhoto': 'Take photo',
|
|
139
|
148
|
'tasks.cameraDenied': 'Camera permission denied.',
|
|
|
@@ -153,6 +162,7 @@ const strings: Record<Language, Record<string, string>> = {
|
|
153
|
162
|
'fields.nameRequired': 'Field name is required.',
|
|
154
|
163
|
'fields.areaInvalid': 'Area must be a number.',
|
|
155
|
164
|
'fields.saved': 'Saved.',
|
|
|
165
|
+ 'fields.saving': 'Saving...',
|
|
156
|
166
|
'fields.name': 'Field name',
|
|
157
|
167
|
'fields.area': 'Area (ha)',
|
|
158
|
168
|
'fields.areaPlaceholder': 'e.g. 1.5',
|
|
|
@@ -169,6 +179,10 @@ const strings: Record<Language, Record<string, string>> = {
|
|
169
|
179
|
'fields.unnamed': 'Unnamed field',
|
|
170
|
180
|
'fields.areaLabel': 'Area:',
|
|
171
|
181
|
'fields.photo': 'Field photo',
|
|
|
182
|
+ 'fields.addMedia': 'Add media',
|
|
|
183
|
+ 'fields.pickFromGallery': 'Pick from gallery',
|
|
|
184
|
+ 'fields.takeMedia': 'Take photo / video',
|
|
|
185
|
+ 'fields.videoSelected': 'Video selected.',
|
|
172
|
186
|
'fields.pickPhoto': 'Pick photo',
|
|
173
|
187
|
'fields.takePhoto': 'Take photo',
|
|
174
|
188
|
'fields.noPhoto': 'No photo selected.',
|
|
|
@@ -195,6 +209,7 @@ const strings: Record<Language, Record<string, string>> = {
|
|
195
|
209
|
'observations.loading': 'Loading observations...',
|
|
196
|
210
|
'observations.empty': 'No observations yet.',
|
|
197
|
211
|
'observations.saved': 'Saved.',
|
|
|
212
|
+ 'observations.saving': 'Saving...',
|
|
198
|
213
|
'observations.field': 'Field',
|
|
199
|
214
|
'observations.crop': 'Crop',
|
|
200
|
215
|
'observations.type': 'Type',
|
|
|
@@ -218,6 +233,9 @@ const strings: Record<Language, Record<string, string>> = {
|
|
218
|
233
|
'observations.edit': 'Edit observation',
|
|
219
|
234
|
'observations.update': 'Update observation',
|
|
220
|
235
|
'observations.photo': 'Observation photo',
|
|
|
236
|
+ 'observations.addMedia': 'Add media',
|
|
|
237
|
+ 'observations.pickFromGallery': 'Pick from gallery',
|
|
|
238
|
+ 'observations.takeMedia': 'Take photo / video',
|
|
221
|
239
|
'observations.pickPhoto': 'Pick photo',
|
|
222
|
240
|
'observations.takePhoto': 'Take photo',
|
|
223
|
241
|
'observations.noPhoto': 'No photo selected.',
|
|
|
@@ -225,6 +243,7 @@ const strings: Record<Language, Record<string, string>> = {
|
|
225
|
243
|
'harvests.loading': 'Loading harvest records...',
|
|
226
|
244
|
'harvests.empty': 'No harvest records yet.',
|
|
227
|
245
|
'harvests.saved': 'Saved.',
|
|
|
246
|
+ 'harvests.saving': 'Saving...',
|
|
228
|
247
|
'harvests.new': 'New harvest',
|
|
229
|
248
|
'harvests.field': 'Field',
|
|
230
|
249
|
'harvests.crop': 'Crop',
|
|
|
@@ -239,6 +258,9 @@ const strings: Record<Language, Record<string, string>> = {
|
|
239
|
258
|
'harvests.notes': 'Notes',
|
|
240
|
259
|
'harvests.notesPlaceholder': 'Quality, weather, labor notes...',
|
|
241
|
260
|
'harvests.photo': 'Harvest photo',
|
|
|
261
|
+ 'harvests.addMedia': 'Add media',
|
|
|
262
|
+ 'harvests.pickFromGallery': 'Pick from gallery',
|
|
|
263
|
+ 'harvests.takeMedia': 'Take photo / video',
|
|
242
|
264
|
'harvests.pickPhoto': 'Pick photo',
|
|
243
|
265
|
'harvests.takePhoto': 'Take photo',
|
|
244
|
266
|
'harvests.noPhoto': 'No photo selected.',
|
|
|
@@ -263,6 +285,7 @@ const strings: Record<Language, Record<string, string>> = {
|
|
263
|
285
|
'sales.loading': 'Loading sales records...',
|
|
264
|
286
|
'sales.empty': 'No sales records yet.',
|
|
265
|
287
|
'sales.saved': 'Saved.',
|
|
|
288
|
+ 'sales.saving': 'Saving...',
|
|
266
|
289
|
'sales.new': 'New sale',
|
|
267
|
290
|
'sales.field': 'Field',
|
|
268
|
291
|
'sales.crop': 'Crop',
|
|
|
@@ -291,6 +314,8 @@ const strings: Record<Language, Record<string, string>> = {
|
|
291
|
314
|
'sales.deleteTitle': 'Delete sales record?',
|
|
292
|
315
|
'sales.deleteMessage': 'This action cannot be undone.',
|
|
293
|
316
|
'sales.cancel': 'Cancel',
|
|
|
317
|
+ 'sales.pickFromGallery': 'Pick from gallery',
|
|
|
318
|
+ 'sales.takeMedia': 'Take photo / video',
|
|
294
|
319
|
'sales.save': 'Save sale',
|
|
295
|
320
|
'sales.untitled': 'Sale',
|
|
296
|
321
|
'sales.noField': 'No field',
|
|
|
@@ -301,6 +326,7 @@ const strings: Record<Language, Record<string, string>> = {
|
|
301
|
326
|
'costs.loading': 'Loading costs...',
|
|
302
|
327
|
'costs.empty': 'No cost records yet.',
|
|
303
|
328
|
'costs.saved': 'Saved.',
|
|
|
329
|
+ 'costs.saving': 'Saving...',
|
|
304
|
330
|
'costs.new': 'New cost',
|
|
305
|
331
|
'costs.field': 'Field',
|
|
306
|
332
|
'costs.crop': 'Crop (optional)',
|
|
|
@@ -324,6 +350,9 @@ const strings: Record<Language, Record<string, string>> = {
|
|
324
|
350
|
'costs.notes': 'Notes',
|
|
325
|
351
|
'costs.notesPlaceholder': 'Receipt, usage, purpose...',
|
|
326
|
352
|
'costs.photo': 'Receipt photo',
|
|
|
353
|
+ 'costs.addMedia': 'Add media',
|
|
|
354
|
+ 'costs.pickFromGallery': 'Pick from gallery',
|
|
|
355
|
+ 'costs.takeMedia': 'Take photo / video',
|
|
327
|
356
|
'costs.pickPhoto': 'Pick photo',
|
|
328
|
357
|
'costs.takePhoto': 'Take photo',
|
|
329
|
358
|
'costs.noPhoto': 'No photo selected.',
|
|
|
@@ -339,10 +368,6 @@ const strings: Record<Language, Record<string, string>> = {
|
|
339
|
368
|
'costs.untitled': 'Cost',
|
|
340
|
369
|
'costs.noField': 'No field',
|
|
341
|
370
|
'costs.noCrop': 'No crop',
|
|
342
|
|
- 'units.kg': 'กก.',
|
|
343
|
|
- 'units.g': 'กรัม',
|
|
344
|
|
- 'units.ton': 'ตัน',
|
|
345
|
|
- 'units.pcs': 'ชิ้น',
|
|
346
|
371
|
'demo.field.north': 'North Field',
|
|
347
|
372
|
'demo.field.northNote': 'Loamy soil · drip irrigation',
|
|
348
|
373
|
'demo.field.river': 'River Plot',
|
|
|
@@ -396,12 +421,14 @@ const strings: Record<Language, Record<string, string>> = {
|
|
396
|
421
|
'crops.loading': 'Loading crops...',
|
|
397
|
422
|
'crops.empty': 'No crops yet.',
|
|
398
|
423
|
'crops.saved': 'Saved.',
|
|
|
424
|
+ 'crops.saving': 'Saving...',
|
|
399
|
425
|
'crops.field': 'Field',
|
|
400
|
426
|
'crops.selectField': 'Select field',
|
|
401
|
427
|
'crops.name': 'Crop name',
|
|
402
|
428
|
'crops.variety': 'Variety',
|
|
403
|
429
|
'crops.planting': 'Planting date',
|
|
404
|
430
|
'crops.harvest': 'Expected harvest',
|
|
|
431
|
+ 'crops.selectDate': 'Select date',
|
|
405
|
432
|
'crops.namePlaceholder': 'e.g. Tomato',
|
|
406
|
433
|
'crops.varietyPlaceholder': 'e.g. Cherry',
|
|
407
|
434
|
'crops.plantingPlaceholder': 'YYYY-MM-DD',
|
|
|
@@ -418,6 +445,9 @@ const strings: Record<Language, Record<string, string>> = {
|
|
418
|
445
|
'crops.save': 'Save crop',
|
|
419
|
446
|
'crops.new': 'New crop',
|
|
420
|
447
|
'crops.photo': 'Crop photo',
|
|
|
448
|
+ 'crops.addMedia': 'Add media',
|
|
|
449
|
+ 'crops.pickFromGallery': 'Pick from gallery',
|
|
|
450
|
+ 'crops.takeMedia': 'Take photo / video',
|
|
421
|
451
|
'crops.pickPhoto': 'Pick photo',
|
|
422
|
452
|
'crops.takePhoto': 'Take photo',
|
|
423
|
453
|
'crops.noPhoto': 'No photo selected.',
|
|
|
@@ -428,6 +458,7 @@ const strings: Record<Language, Record<string, string>> = {
|
|
428
|
458
|
'crops.cancel': 'Cancel',
|
|
429
|
459
|
},
|
|
430
|
460
|
th: {
|
|
|
461
|
+ 'common.close': 'ปิด',
|
|
431
|
462
|
'tabs.home': 'หน้าแรก',
|
|
432
|
463
|
'tabs.explore': 'สำรวจ',
|
|
433
|
464
|
'tabs.onnx': 'สแกนใบ',
|
|
|
@@ -448,7 +479,7 @@ const strings: Record<Language, Record<string, string>> = {
|
|
448
|
479
|
'setup.noPhoto': 'ยังไม่ได้เลือกรูป',
|
|
449
|
480
|
'setup.uploadPhoto': 'อัปโหลดรูป',
|
|
450
|
481
|
'setup.exportTitle': 'ส่งออกข้อมูล',
|
|
451
|
|
- 'setup.exportHint': 'ดาวน์โหลดข้อมูลในเครื่องเป็นไฟล์ CSV',
|
|
|
482
|
+ 'setup.exportHint': 'ดาวน์โหลดข้อมูลในเครื่องเป็นไฟล์ JSON',
|
|
452
|
483
|
'setup.exportButton': 'ส่งออกข้อมูล',
|
|
453
|
484
|
'setup.exported': 'ส่งออกข้อมูลแล้ว',
|
|
454
|
485
|
'setup.exportError': 'ส่งออกข้อมูลไม่สำเร็จ',
|
|
|
@@ -460,6 +491,7 @@ const strings: Record<Language, Record<string, string>> = {
|
|
460
|
491
|
'setup.language': 'ภาษา',
|
|
461
|
492
|
'setup.lang.en': 'English',
|
|
462
|
493
|
'setup.lang.th': 'ไทย',
|
|
|
494
|
+ 'setup.lang.ja': '日本語',
|
|
463
|
495
|
'setup.currency': 'สกุลเงินเริ่มต้น',
|
|
464
|
496
|
'setup.currencyPlaceholder': 'เช่น THB',
|
|
465
|
497
|
'setup.currency.thb': 'บาท (THB)',
|
|
|
@@ -543,13 +575,20 @@ const strings: Record<Language, Record<string, string>> = {
|
|
543
|
575
|
'tasks.title': 'งานประจำวัน',
|
|
544
|
576
|
'tasks.subtitle': 'บันทึกงานประจำวันของแปลงวันนี้',
|
|
545
|
577
|
'tasks.loading': 'กำลังโหลดงาน...',
|
|
|
578
|
+ 'tasks.saving': 'กำลังบันทึก...',
|
|
|
579
|
+ 'tasks.saved': 'บันทึกแล้ว',
|
|
546
|
580
|
'tasks.empty': 'ยังไม่มีงานที่ตั้งไว้',
|
|
547
|
581
|
'tasks.pending': 'รอดำเนินการ',
|
|
548
|
582
|
'tasks.done': 'เสร็จแล้ว',
|
|
549
|
583
|
'tasks.complete': 'ทำเสร็จแล้ว',
|
|
|
584
|
+ 'tasks.save': 'บันทึก',
|
|
|
585
|
+ 'tasks.open': 'กำลังดำเนินการ',
|
|
550
|
586
|
'tasks.undo': 'ย้อนกลับ',
|
|
551
|
587
|
'tasks.notePlaceholder': 'เพิ่มบันทึกสำหรับวันนี้...',
|
|
552
|
588
|
'tasks.photo': 'รูปงาน',
|
|
|
589
|
+ 'tasks.addMedia': 'เพิ่มสื่อ',
|
|
|
590
|
+ 'tasks.pickFromGallery': 'เลือกรูปจากแกลเลอรี',
|
|
|
591
|
+ 'tasks.takeMedia': 'ถ่ายรูป / วิดีโอ',
|
|
553
|
592
|
'tasks.pickPhoto': 'เลือกรูป',
|
|
554
|
593
|
'tasks.takePhoto': 'ถ่ายรูป',
|
|
555
|
594
|
'tasks.cameraDenied': 'ไม่ได้รับอนุญาตให้ใช้กล้อง',
|
|
|
@@ -569,6 +608,7 @@ const strings: Record<Language, Record<string, string>> = {
|
|
569
|
608
|
'fields.nameRequired': 'ต้องระบุชื่อแปลง',
|
|
570
|
609
|
'fields.areaInvalid': 'พื้นที่ต้องเป็นตัวเลข',
|
|
571
|
610
|
'fields.saved': 'บันทึกแล้ว',
|
|
|
611
|
+ 'fields.saving': 'กำลังบันทึก...',
|
|
572
|
612
|
'fields.name': 'ชื่อแปลง',
|
|
573
|
613
|
'fields.area': 'พื้นที่ (ไร่)',
|
|
574
|
614
|
'fields.areaPlaceholder': 'เช่น 1.5',
|
|
|
@@ -585,6 +625,10 @@ const strings: Record<Language, Record<string, string>> = {
|
|
585
|
625
|
'fields.unnamed': 'แปลงไม่มีชื่อ',
|
|
586
|
626
|
'fields.areaLabel': 'พื้นที่:',
|
|
587
|
627
|
'fields.photo': 'รูปแปลง',
|
|
|
628
|
+ 'fields.addMedia': 'เพิ่มสื่อ',
|
|
|
629
|
+ 'fields.pickFromGallery': 'เลือกรูปจากแกลเลอรี',
|
|
|
630
|
+ 'fields.takeMedia': 'ถ่ายรูป / วิดีโอ',
|
|
|
631
|
+ 'fields.videoSelected': 'เลือกวิดีโอแล้ว',
|
|
588
|
632
|
'fields.pickPhoto': 'เลือกรูป',
|
|
589
|
633
|
'fields.takePhoto': 'ถ่ายรูป',
|
|
590
|
634
|
'fields.noPhoto': 'ยังไม่ได้เลือกรูป',
|
|
|
@@ -611,6 +655,7 @@ const strings: Record<Language, Record<string, string>> = {
|
|
611
|
655
|
'observations.loading': 'กำลังโหลดบันทึก...',
|
|
612
|
656
|
'observations.empty': 'ยังไม่มีบันทึก',
|
|
613
|
657
|
'observations.saved': 'บันทึกแล้ว',
|
|
|
658
|
+ 'observations.saving': 'กำลังบันทึก...',
|
|
614
|
659
|
'observations.field': 'แปลง',
|
|
615
|
660
|
'observations.crop': 'พืช',
|
|
616
|
661
|
'observations.type': 'ประเภท',
|
|
|
@@ -634,6 +679,9 @@ const strings: Record<Language, Record<string, string>> = {
|
|
634
|
679
|
'observations.edit': 'แก้ไขบันทึก',
|
|
635
|
680
|
'observations.update': 'อัปเดตบันทึก',
|
|
636
|
681
|
'observations.photo': 'รูปประกอบ',
|
|
|
682
|
+ 'observations.addMedia': 'เพิ่มสื่อ',
|
|
|
683
|
+ 'observations.pickFromGallery': 'เลือกรูปจากแกลเลอรี',
|
|
|
684
|
+ 'observations.takeMedia': 'ถ่ายรูป / วิดีโอ',
|
|
637
|
685
|
'observations.pickPhoto': 'เลือกรูป',
|
|
638
|
686
|
'observations.takePhoto': 'ถ่ายรูป',
|
|
639
|
687
|
'observations.noPhoto': 'ยังไม่ได้เลือกรูป',
|
|
|
@@ -641,6 +689,7 @@ const strings: Record<Language, Record<string, string>> = {
|
|
641
|
689
|
'harvests.loading': 'กำลังโหลดการเก็บเกี่ยว...',
|
|
642
|
690
|
'harvests.empty': 'ยังไม่มีบันทึกการเก็บเกี่ยว',
|
|
643
|
691
|
'harvests.saved': 'บันทึกแล้ว',
|
|
|
692
|
+ 'harvests.saving': 'กำลังบันทึก...',
|
|
644
|
693
|
'harvests.new': 'เพิ่มการเก็บเกี่ยว',
|
|
645
|
694
|
'harvests.field': 'แปลง',
|
|
646
|
695
|
'harvests.crop': 'พืช',
|
|
|
@@ -655,6 +704,9 @@ const strings: Record<Language, Record<string, string>> = {
|
|
655
|
704
|
'harvests.notes': 'บันทึก',
|
|
656
|
705
|
'harvests.notesPlaceholder': 'คุณภาพ สภาพอากาศ แรงงาน...',
|
|
657
|
706
|
'harvests.photo': 'รูปการเก็บเกี่ยว',
|
|
|
707
|
+ 'harvests.addMedia': 'เพิ่มสื่อ',
|
|
|
708
|
+ 'harvests.pickFromGallery': 'เลือกรูปจากแกลเลอรี',
|
|
|
709
|
+ 'harvests.takeMedia': 'ถ่ายรูป / วิดีโอ',
|
|
658
|
710
|
'harvests.pickPhoto': 'เลือกรูป',
|
|
659
|
711
|
'harvests.takePhoto': 'ถ่ายรูป',
|
|
660
|
712
|
'harvests.noPhoto': 'ยังไม่ได้เลือกรูป',
|
|
|
@@ -675,6 +727,7 @@ const strings: Record<Language, Record<string, string>> = {
|
|
675
|
727
|
'sales.loading': 'กำลังโหลดการขาย...',
|
|
676
|
728
|
'sales.empty': 'ยังไม่มีบันทึกการขาย',
|
|
677
|
729
|
'sales.saved': 'บันทึกแล้ว',
|
|
|
730
|
+ 'sales.saving': 'กำลังบันทึก...',
|
|
678
|
731
|
'sales.new': 'เพิ่มการขาย',
|
|
679
|
732
|
'sales.field': 'แปลง',
|
|
680
|
733
|
'sales.crop': 'พืช',
|
|
|
@@ -703,6 +756,8 @@ const strings: Record<Language, Record<string, string>> = {
|
|
703
|
756
|
'sales.deleteTitle': 'ลบบันทึกการขาย?',
|
|
704
|
757
|
'sales.deleteMessage': 'การลบไม่สามารถย้อนกลับได้',
|
|
705
|
758
|
'sales.cancel': 'ยกเลิก',
|
|
|
759
|
+ 'sales.pickFromGallery': 'เลือกรูปจากแกลเลอรี',
|
|
|
760
|
+ 'sales.takeMedia': 'ถ่ายรูป / วิดีโอ',
|
|
706
|
761
|
'sales.save': 'บันทึกการขาย',
|
|
707
|
762
|
'sales.untitled': 'การขาย',
|
|
708
|
763
|
'sales.noField': 'ไม่มีแปลง',
|
|
|
@@ -713,6 +768,7 @@ const strings: Record<Language, Record<string, string>> = {
|
|
713
|
768
|
'costs.loading': 'กำลังโหลดต้นทุน...',
|
|
714
|
769
|
'costs.empty': 'ยังไม่มีบันทึกต้นทุน',
|
|
715
|
770
|
'costs.saved': 'บันทึกแล้ว',
|
|
|
771
|
+ 'costs.saving': 'กำลังบันทึก...',
|
|
716
|
772
|
'costs.new': 'เพิ่มต้นทุน',
|
|
717
|
773
|
'costs.field': 'แปลง',
|
|
718
|
774
|
'costs.crop': 'พืช (ไม่บังคับ)',
|
|
|
@@ -736,6 +792,9 @@ const strings: Record<Language, Record<string, string>> = {
|
|
736
|
792
|
'costs.notes': 'บันทึก',
|
|
737
|
793
|
'costs.notesPlaceholder': 'ใบเสร็จ การใช้งาน วัตถุประสงค์...',
|
|
738
|
794
|
'costs.photo': 'รูปใบเสร็จ',
|
|
|
795
|
+ 'costs.addMedia': 'เพิ่มสื่อ',
|
|
|
796
|
+ 'costs.pickFromGallery': 'เลือกรูปจากแกลเลอรี',
|
|
|
797
|
+ 'costs.takeMedia': 'ถ่ายรูป / วิดีโอ',
|
|
739
|
798
|
'costs.pickPhoto': 'เลือกรูป',
|
|
740
|
799
|
'costs.takePhoto': 'ถ่ายรูป',
|
|
741
|
800
|
'costs.noPhoto': 'ยังไม่ได้เลือกรูป',
|
|
|
@@ -804,12 +863,14 @@ const strings: Record<Language, Record<string, string>> = {
|
|
804
|
863
|
'crops.loading': 'กำลังโหลดพืช...',
|
|
805
|
864
|
'crops.empty': 'ยังไม่มีพืช',
|
|
806
|
865
|
'crops.saved': 'บันทึกแล้ว',
|
|
|
866
|
+ 'crops.saving': 'กำลังบันทึก...',
|
|
807
|
867
|
'crops.field': 'แปลง',
|
|
808
|
868
|
'crops.selectField': 'เลือกแปลง',
|
|
809
|
869
|
'crops.name': 'ชื่อพืช',
|
|
810
|
870
|
'crops.variety': 'สายพันธุ์',
|
|
811
|
871
|
'crops.planting': 'วันที่ปลูก',
|
|
812
|
872
|
'crops.harvest': 'คาดว่าจะเก็บเกี่ยว',
|
|
|
873
|
+ 'crops.selectDate': 'เลือกวันที่',
|
|
813
|
874
|
'crops.namePlaceholder': 'เช่น มะเขือเทศ',
|
|
814
|
875
|
'crops.varietyPlaceholder': 'เช่น เชอรี่',
|
|
815
|
876
|
'crops.plantingPlaceholder': 'YYYY-MM-DD',
|
|
|
@@ -826,6 +887,9 @@ const strings: Record<Language, Record<string, string>> = {
|
|
826
|
887
|
'crops.save': 'บันทึกพืช',
|
|
827
|
888
|
'crops.new': 'เพิ่มพืช',
|
|
828
|
889
|
'crops.photo': 'รูปพืช',
|
|
|
890
|
+ 'crops.addMedia': 'เพิ่มสื่อ',
|
|
|
891
|
+ 'crops.pickFromGallery': 'เลือกรูปจากแกลเลอรี',
|
|
|
892
|
+ 'crops.takeMedia': 'ถ่ายรูป / วิดีโอ',
|
|
829
|
893
|
'crops.pickPhoto': 'เลือกรูป',
|
|
830
|
894
|
'crops.takePhoto': 'ถ่ายรูป',
|
|
831
|
895
|
'crops.noPhoto': 'ยังไม่ได้เลือกรูป',
|
|
|
@@ -835,12 +899,471 @@ const strings: Record<Language, Record<string, string>> = {
|
|
835
|
899
|
'crops.update': 'อัปเดตพืช',
|
|
836
|
900
|
'crops.cancel': 'ยกเลิก',
|
|
837
|
901
|
},
|
|
|
902
|
+ ja: {
|
|
|
903
|
+ 'common.close': '閉じる',
|
|
|
904
|
+ 'tabs.home': 'ホーム',
|
|
|
905
|
+ 'tabs.explore': '探索',
|
|
|
906
|
+ 'tabs.onnx': '葉スキャン',
|
|
|
907
|
+ 'tabs.setup': '設定',
|
|
|
908
|
+ 'tabs.blog': 'ブログ',
|
|
|
909
|
+ 'tabs.tasks': '日次タスク',
|
|
|
910
|
+ 'tabs.fields': '圃場',
|
|
|
911
|
+ 'tabs.logbook': 'ログブック',
|
|
|
912
|
+ 'tabs.taskHistory': '履歴',
|
|
|
913
|
+ 'setup.title': 'ユーザー設定',
|
|
|
914
|
+ 'setup.profile': 'プロフィール',
|
|
|
915
|
+ 'setup.loading': '読み込み中...',
|
|
|
916
|
+ 'setup.loaded': '保存したプロフィールを読み込みました。',
|
|
|
917
|
+ 'setup.none': 'プロフィールがまだありません。入力して保存してください。',
|
|
|
918
|
+ 'setup.saving': '保存中...',
|
|
|
919
|
+ 'setup.saved': 'ローカルに保存しました。',
|
|
|
920
|
+ 'setup.photo': 'プロフィール写真',
|
|
|
921
|
+ 'setup.noPhoto': '写真が選択されていません。',
|
|
|
922
|
+ 'setup.uploadPhoto': '写真をアップロード',
|
|
|
923
|
+ 'setup.exportTitle': 'データを書き出し',
|
|
|
924
|
+ 'setup.exportHint': 'ローカルデータをJSONとしてダウンロードします。',
|
|
|
925
|
+ 'setup.exportButton': 'データを書き出し',
|
|
|
926
|
+ 'setup.exported': 'データを書き出しました。',
|
|
|
927
|
+ 'setup.exportError': '書き出しに失敗しました。',
|
|
|
928
|
+ 'setup.name': '名前',
|
|
|
929
|
+ 'setup.farmName': '農場名',
|
|
|
930
|
+ 'setup.location': '所在地',
|
|
|
931
|
+ 'setup.save': 'ローカルに保存',
|
|
|
932
|
+ 'setup.saveIndicator': '保存しました!',
|
|
|
933
|
+ 'setup.language': '言語',
|
|
|
934
|
+ 'setup.lang.en': 'English',
|
|
|
935
|
+ 'setup.lang.th': 'ไทย',
|
|
|
936
|
+ 'setup.lang.ja': '日本語',
|
|
|
937
|
+ 'setup.currency': '既定の通貨',
|
|
|
938
|
+ 'setup.currencyPlaceholder': '例: JPY',
|
|
|
939
|
+ 'setup.currency.thb': 'THB',
|
|
|
940
|
+ 'setup.currency.usd': 'USD',
|
|
|
941
|
+ 'setup.currency.eur': 'EUR',
|
|
|
942
|
+ 'setup.currency.jpy': 'JPY',
|
|
|
943
|
+ 'setup.demoTitle': 'デモデータ',
|
|
|
944
|
+ 'setup.demoHint': 'サンプルの圃場、作物、観察、履歴を挿入します。',
|
|
|
945
|
+ 'setup.demoButton': 'デモデータを挿入',
|
|
|
946
|
+ 'setup.demoInserting': 'デモデータを挿入中...',
|
|
|
947
|
+ 'setup.demoInserted': 'デモデータを挿入しました。',
|
|
|
948
|
+ 'setup.demoExists': 'デモデータは既にあります。',
|
|
|
949
|
+ 'setup.demoError': 'デモデータの挿入に失敗しました。',
|
|
|
950
|
+ 'setup.demoClearButton': 'デモデータを削除',
|
|
|
951
|
+ 'setup.demoClearing': 'デモデータを削除中...',
|
|
|
952
|
+ 'setup.demoCleared': 'デモデータを削除しました。',
|
|
|
953
|
+ 'setup.demoClearError': 'デモデータの削除に失敗しました。',
|
|
|
954
|
+ 'setup.demoClearedUndo': 'デモデータを削除しました。',
|
|
|
955
|
+ 'setup.demoUndo': '元に戻す',
|
|
|
956
|
+ 'setup.demoUndoDone': 'デモデータを復元しました。',
|
|
|
957
|
+ 'setup.demoUndoError': '元に戻せませんでした。',
|
|
|
958
|
+ 'onnx.title': '葉の分類',
|
|
|
959
|
+ 'onnx.howTitle': 'ONNXモデルの使い方',
|
|
|
960
|
+ 'onnx.howBody':
|
|
|
961
|
+ 'このページはPlantVillage MobileNetV3-Smallモデルを読み込み、224x224のRGBテンソルで推論します。入力は各チャンネル0..1に正規化されます。',
|
|
|
962
|
+ 'onnx.sampleTitle': 'サンプルコード',
|
|
|
963
|
+ 'onnx.testTitle': 'モデルをテスト',
|
|
|
964
|
+ 'onnx.pickImage': '画像を選ぶ',
|
|
|
965
|
+ 'onnx.runModel': 'モデルを実行',
|
|
|
966
|
+ 'onnx.status.pick': '画像を選択してモデルを実行します。',
|
|
|
967
|
+ 'onnx.status.ready': '準備完了。「モデルを実行」をタップしてください。',
|
|
|
968
|
+ 'onnx.status.preprocessing': '画像を前処理中...',
|
|
|
969
|
+ 'onnx.status.running': 'PlantVillageモデルを実行中...',
|
|
|
970
|
+ 'onnx.status.done': '完了。',
|
|
|
971
|
+ 'onnx.status.nativeMissing': 'ONNX runtimeが利用できません。dev buildを使用してください。',
|
|
|
972
|
+ 'onnx.topPredictions': '上位の予測',
|
|
|
973
|
+ 'blog.title': 'ブログ記事',
|
|
|
974
|
+ 'blog.loading': '記事を読み込み中...',
|
|
|
975
|
+ 'blog.error': '記事の読み込みに失敗しました。',
|
|
|
976
|
+ 'blog.empty': '記事がありません。',
|
|
|
977
|
+ 'blog.loadMore': 'さらに読み込む',
|
|
|
978
|
+ 'blog.loadingMore': 'さらに読み込み中...',
|
|
|
979
|
+ 'blog.language': '言語',
|
|
|
980
|
+ 'blog.lang.en': 'English',
|
|
|
981
|
+ 'blog.lang.th': 'ไทย',
|
|
|
982
|
+ 'blog.lang.ja': '日本語',
|
|
|
983
|
+ 'blog.lang.zh': '中文',
|
|
|
984
|
+ 'home.badge': 'Smartfarming Lite',
|
|
|
985
|
+ 'home.title': '圃場・作物・観察を、農場から離れずに記録。',
|
|
|
986
|
+ 'home.subtitle': '日々の作業、写真、作物履歴をオフラインで管理。',
|
|
|
987
|
+ 'home.openLogbook': 'ログブックを開く',
|
|
|
988
|
+ 'home.todayTasks': '今日のタスク',
|
|
|
989
|
+ 'home.quickActions': 'クイック操作',
|
|
|
990
|
+ 'home.fields': '圃場',
|
|
|
991
|
+ 'home.fieldsHint': '面積、メモ、写真を追加。',
|
|
|
992
|
+ 'home.crops': '作物',
|
|
|
993
|
+ 'home.cropsHint': '定植日と収穫予定。',
|
|
|
994
|
+ 'home.observations': '観察',
|
|
|
995
|
+ 'home.observationsHint': 'メモ、深刻度、画像。',
|
|
|
996
|
+ 'home.onnx': '葉スキャン',
|
|
|
997
|
+ 'home.onnxHint': '葉の分類を実行。',
|
|
|
998
|
+ 'home.harvests': '収穫',
|
|
|
999
|
+ 'home.harvestsHint': '収量と収穫記録。',
|
|
|
1000
|
+ 'home.sales': '販売',
|
|
|
1001
|
+ 'home.salesHint': '販売記録と買い手。',
|
|
|
1002
|
+ 'home.costs': 'コスト',
|
|
|
1003
|
+ 'home.costsHint': '支出を記録。',
|
|
|
1004
|
+ 'home.todayTitle': '今日',
|
|
|
1005
|
+ 'home.todayCardTitle': '圃場作業を記録',
|
|
|
1006
|
+ 'home.todayCardBody': '観察メモを残し、写真を添付して次回のための履歴を整理。',
|
|
|
1007
|
+ 'home.openTasks': 'タスクを開く',
|
|
|
1008
|
+ 'home.taskHistory': 'タスク履歴',
|
|
|
1009
|
+ 'home.learnAnalyze': '学ぶ・分析する',
|
|
|
1010
|
+ 'home.blogs': 'ブログ',
|
|
|
1011
|
+ 'home.blogsHint': 'スマート農業の最新記事。',
|
|
|
1012
|
+ 'home.profile': 'プロフィール',
|
|
|
1013
|
+ 'home.profileHint': '農場情報と言語設定。',
|
|
|
1014
|
+ 'home.count.tasks': 'タスク',
|
|
|
1015
|
+ 'home.count.history': '履歴',
|
|
|
1016
|
+ 'tasks.title': '日次タスク',
|
|
|
1017
|
+ 'tasks.subtitle': '今日の圃場作業を記録。',
|
|
|
1018
|
+ 'tasks.loading': 'タスクを読み込み中...',
|
|
|
1019
|
+ 'tasks.saving': '保存中...',
|
|
|
1020
|
+ 'tasks.saved': '保存しました。',
|
|
|
1021
|
+ 'tasks.empty': 'タスクがまだありません。',
|
|
|
1022
|
+ 'tasks.pending': '未完了',
|
|
|
1023
|
+ 'tasks.done': '完了',
|
|
|
1024
|
+ 'tasks.complete': '完了にする',
|
|
|
1025
|
+ 'tasks.save': '保存',
|
|
|
1026
|
+ 'tasks.open': '進行中',
|
|
|
1027
|
+ 'tasks.undo': '元に戻す',
|
|
|
1028
|
+ 'tasks.notePlaceholder': '今日のメモを追加...',
|
|
|
1029
|
+ 'tasks.photo': 'タスク写真',
|
|
|
1030
|
+ 'tasks.addMedia': 'メディアを追加',
|
|
|
1031
|
+ 'tasks.pickFromGallery': 'ギャラリーから選ぶ',
|
|
|
1032
|
+ 'tasks.takeMedia': '写真 / 動画を撮る',
|
|
|
1033
|
+ 'tasks.pickPhoto': '写真を選ぶ',
|
|
|
1034
|
+ 'tasks.takePhoto': '写真を撮る',
|
|
|
1035
|
+ 'tasks.cameraDenied': 'カメラの権限がありません。',
|
|
|
1036
|
+ 'tasks.cameraError': 'カメラが利用できません。',
|
|
|
1037
|
+ 'tasks.historyTitle': 'タスク履歴',
|
|
|
1038
|
+ 'tasks.historyEmpty': 'タスク履歴がまだありません。',
|
|
|
1039
|
+ 'tasks.back': 'タスクに戻る',
|
|
|
1040
|
+ 'tasks.default.fieldCheck': '圃場チェック',
|
|
|
1041
|
+ 'tasks.default.fieldCheckDesc': '圃場の状態とメモを簡単に記録。',
|
|
|
1042
|
+ 'tasks.default.scouting': '病害虫の確認',
|
|
|
1043
|
+ 'tasks.default.scoutingDesc': '葉を確認して深刻度を記録。',
|
|
|
1044
|
+ 'tasks.default.sensors': 'センサー計測',
|
|
|
1045
|
+ 'tasks.default.sensorsDesc': '土壌水分や天候の記録。',
|
|
|
1046
|
+ 'fields.title': '圃場',
|
|
|
1047
|
+ 'fields.loading': '圃場を読み込み中...',
|
|
|
1048
|
+ 'fields.empty': '圃場がまだありません。',
|
|
|
1049
|
+ 'fields.nameRequired': '圃場名は必須です。',
|
|
|
1050
|
+ 'fields.areaInvalid': '面積は数値で入力してください。',
|
|
|
1051
|
+ 'fields.saved': '保存しました。',
|
|
|
1052
|
+ 'fields.saving': '保存中...',
|
|
|
1053
|
+ 'fields.name': '圃場名',
|
|
|
1054
|
+ 'fields.area': '面積 (ha)',
|
|
|
1055
|
+ 'fields.areaPlaceholder': '例: 1.5',
|
|
|
1056
|
+ 'fields.notes': 'メモ',
|
|
|
1057
|
+ 'fields.notesPlaceholder': '土壌、灌漑、目印など...',
|
|
|
1058
|
+ 'fields.save': '圃場を保存',
|
|
|
1059
|
+ 'fields.update': '圃場を更新',
|
|
|
1060
|
+ 'fields.cancel': 'キャンセル',
|
|
|
1061
|
+ 'fields.edit': '編集',
|
|
|
1062
|
+ 'fields.delete': '削除',
|
|
|
1063
|
+ 'fields.deleteTitle': '圃場を削除しますか?',
|
|
|
1064
|
+ 'fields.deleteMessage': 'この操作は取り消せません。',
|
|
|
1065
|
+ 'fields.new': '新しい圃場',
|
|
|
1066
|
+ 'fields.unnamed': '無名の圃場',
|
|
|
1067
|
+ 'fields.areaLabel': '面積:',
|
|
|
1068
|
+ 'fields.photo': '圃場写真',
|
|
|
1069
|
+ 'fields.addMedia': 'メディアを追加',
|
|
|
1070
|
+ 'fields.pickFromGallery': 'ギャラリーから選ぶ',
|
|
|
1071
|
+ 'fields.takeMedia': '写真 / 動画を撮る',
|
|
|
1072
|
+ 'fields.videoSelected': '動画を選択しました。',
|
|
|
1073
|
+ 'fields.pickPhoto': '写真を選ぶ',
|
|
|
1074
|
+ 'fields.takePhoto': '写真を撮る',
|
|
|
1075
|
+ 'fields.noPhoto': '写真が選択されていません。',
|
|
|
1076
|
+ 'fields.updatedAt': '更新:',
|
|
|
1077
|
+ 'logbook.title': 'ログブック',
|
|
|
1078
|
+ 'logbook.subtitle': '主要データを管理。',
|
|
|
1079
|
+ 'logbook.fields': '圃場',
|
|
|
1080
|
+ 'logbook.fieldsHint': '面積、メモ、境界。',
|
|
|
1081
|
+ 'logbook.observations': '観察',
|
|
|
1082
|
+ 'logbook.observationsHint': '観察メモと深刻度。',
|
|
|
1083
|
+ 'logbook.crops': '作物',
|
|
|
1084
|
+ 'logbook.cropsHint': '圃場ごとの作物情報。',
|
|
|
1085
|
+ 'logbook.tasks': '日次タスク',
|
|
|
1086
|
+ 'logbook.tasksHint': 'メモ、写真、状態。',
|
|
|
1087
|
+ 'logbook.history': 'タスク履歴',
|
|
|
1088
|
+ 'logbook.historyHint': '日付別の完了記録。',
|
|
|
1089
|
+ 'logbook.harvests': '収穫',
|
|
|
1090
|
+ 'logbook.harvestsHint': '収量と収穫の詳細。',
|
|
|
1091
|
+ 'logbook.sales': '販売',
|
|
|
1092
|
+ 'logbook.salesHint': '販売記録と買い手。',
|
|
|
1093
|
+ 'logbook.costs': 'コスト',
|
|
|
1094
|
+ 'logbook.costsHint': '支出と領収書。',
|
|
|
1095
|
+ 'observations.title': '観察',
|
|
|
1096
|
+ 'observations.loading': '観察を読み込み中...',
|
|
|
1097
|
+ 'observations.empty': '観察がまだありません。',
|
|
|
1098
|
+ 'observations.saved': '保存しました。',
|
|
|
1099
|
+ 'observations.saving': '保存中...',
|
|
|
1100
|
+ 'observations.field': '圃場',
|
|
|
1101
|
+ 'observations.crop': '作物',
|
|
|
1102
|
+ 'observations.type': '種類',
|
|
|
1103
|
+ 'observations.note': 'メモ',
|
|
|
1104
|
+ 'observations.severity': '深刻度',
|
|
|
1105
|
+ 'observations.severityLabel': '深刻度:',
|
|
|
1106
|
+ 'observations.selectField': '圃場を選択',
|
|
|
1107
|
+ 'observations.selectCrop': '作物を選択',
|
|
|
1108
|
+ 'observations.typePlaceholder': '例: 観察',
|
|
|
1109
|
+ 'observations.notePlaceholder': '観察内容を入力してください。',
|
|
|
1110
|
+ 'observations.severityPlaceholder': '0-10',
|
|
|
1111
|
+ 'observations.fieldRequired': '圃場は必須です。',
|
|
|
1112
|
+ 'observations.severityInvalid': '深刻度は数値で入力してください。',
|
|
|
1113
|
+ 'observations.delete': '削除',
|
|
|
1114
|
+ 'observations.noField': '圃場なし',
|
|
|
1115
|
+ 'observations.noCrop': '作物なし',
|
|
|
1116
|
+ 'observations.untitled': '観察',
|
|
|
1117
|
+ 'observations.save': '観察を保存',
|
|
|
1118
|
+ 'observations.new': '新しい観察',
|
|
|
1119
|
+ 'observations.cancel': 'キャンセル',
|
|
|
1120
|
+ 'observations.edit': '観察を編集',
|
|
|
1121
|
+ 'observations.update': '観察を更新',
|
|
|
1122
|
+ 'observations.photo': '観察写真',
|
|
|
1123
|
+ 'observations.addMedia': 'メディアを追加',
|
|
|
1124
|
+ 'observations.pickFromGallery': 'ギャラリーから選ぶ',
|
|
|
1125
|
+ 'observations.takeMedia': '写真 / 動画を撮る',
|
|
|
1126
|
+ 'observations.pickPhoto': '写真を選ぶ',
|
|
|
1127
|
+ 'observations.takePhoto': '写真を撮る',
|
|
|
1128
|
+ 'observations.noPhoto': '写真が選択されていません。',
|
|
|
1129
|
+ 'harvests.title': '収穫記録',
|
|
|
1130
|
+ 'harvests.loading': '収穫記録を読み込み中...',
|
|
|
1131
|
+ 'harvests.empty': '収穫記録がまだありません。',
|
|
|
1132
|
+ 'harvests.saved': '保存しました。',
|
|
|
1133
|
+ 'harvests.saving': '保存中...',
|
|
|
1134
|
+ 'harvests.new': '新しい収穫',
|
|
|
1135
|
+ 'harvests.field': '圃場',
|
|
|
1136
|
+ 'harvests.crop': '作物',
|
|
|
1137
|
+ 'harvests.selectField': '圃場を選択',
|
|
|
1138
|
+ 'harvests.selectCrop': '作物を選択',
|
|
|
1139
|
+ 'harvests.date': '収穫日',
|
|
|
1140
|
+ 'harvests.datePlaceholder': 'YYYY-MM-DD',
|
|
|
1141
|
+ 'harvests.quantity': '数量',
|
|
|
1142
|
+ 'harvests.quantityPlaceholder': '例: 120',
|
|
|
1143
|
+ 'harvests.unit': '単位',
|
|
|
1144
|
+ 'harvests.unitPlaceholder': 'kg',
|
|
|
1145
|
+ 'harvests.notes': 'メモ',
|
|
|
1146
|
+ 'harvests.notesPlaceholder': '品質、天候、人員メモ...',
|
|
|
1147
|
+ 'harvests.photo': '収穫写真',
|
|
|
1148
|
+ 'harvests.addMedia': 'メディアを追加',
|
|
|
1149
|
+ 'harvests.pickFromGallery': 'ギャラリーから選ぶ',
|
|
|
1150
|
+ 'harvests.takeMedia': '写真 / 動画を撮る',
|
|
|
1151
|
+ 'harvests.pickPhoto': '写真を選ぶ',
|
|
|
1152
|
+ 'harvests.takePhoto': '写真を撮る',
|
|
|
1153
|
+ 'harvests.noPhoto': '写真が選択されていません。',
|
|
|
1154
|
+ 'harvests.fieldRequired': '圃場は必須です。',
|
|
|
1155
|
+ 'harvests.cropRequired': '作物は必須です。',
|
|
|
1156
|
+ 'harvests.quantityInvalid': '数量は数値で入力してください。',
|
|
|
1157
|
+ 'harvests.delete': '削除',
|
|
|
1158
|
+ 'harvests.deleteTitle': '収穫記録を削除しますか?',
|
|
|
1159
|
+ 'harvests.deleteMessage': 'この操作は取り消せません。',
|
|
|
1160
|
+ 'harvests.cancel': 'キャンセル',
|
|
|
1161
|
+ 'harvests.save': '収穫を保存',
|
|
|
1162
|
+ 'harvests.untitled': '収穫',
|
|
|
1163
|
+ 'harvests.noField': '圃場なし',
|
|
|
1164
|
+ 'harvests.noCrop': '作物なし',
|
|
|
1165
|
+ 'harvests.edit': '収穫を編集',
|
|
|
1166
|
+ 'harvests.update': '収穫を更新',
|
|
|
1167
|
+ 'sales.title': '販売記録',
|
|
|
1168
|
+ 'sales.loading': '販売記録を読み込み中...',
|
|
|
1169
|
+ 'sales.empty': '販売記録がまだありません。',
|
|
|
1170
|
+ 'sales.saved': '保存しました。',
|
|
|
1171
|
+ 'sales.saving': '保存中...',
|
|
|
1172
|
+ 'sales.new': '新しい販売',
|
|
|
1173
|
+ 'sales.field': '圃場',
|
|
|
1174
|
+ 'sales.crop': '作物',
|
|
|
1175
|
+ 'sales.harvest': '収穫 (任意)',
|
|
|
1176
|
+ 'sales.selectField': '圃場を選択',
|
|
|
1177
|
+ 'sales.selectCrop': '作物を選択',
|
|
|
1178
|
+ 'sales.selectHarvest': '収穫を選択',
|
|
|
1179
|
+ 'sales.noHarvest': '収穫記録がありません',
|
|
|
1180
|
+ 'sales.date': '販売日',
|
|
|
1181
|
+ 'sales.datePlaceholder': 'YYYY-MM-DD',
|
|
|
1182
|
+ 'sales.quantity': '数量',
|
|
|
1183
|
+ 'sales.quantityPlaceholder': '例: 50',
|
|
|
1184
|
+ 'sales.unit': '単位',
|
|
|
1185
|
+ 'sales.unitPlaceholder': 'kg',
|
|
|
1186
|
+ 'sales.price': '価格',
|
|
|
1187
|
+ 'sales.pricePlaceholder': '例: 35',
|
|
|
1188
|
+ 'sales.priceLabel': '価格:',
|
|
|
1189
|
+ 'sales.buyer': '買い手',
|
|
|
1190
|
+ 'sales.buyerPlaceholder': '例: 地元市場',
|
|
|
1191
|
+ 'sales.notes': 'メモ',
|
|
|
1192
|
+ 'sales.notesPlaceholder': '支払い、輸送、品質...',
|
|
|
1193
|
+ 'sales.fieldRequired': '圃場は必須です。',
|
|
|
1194
|
+ 'sales.cropRequired': '作物は必須です。',
|
|
|
1195
|
+ 'sales.quantityInvalid': '数量は数値で入力してください。',
|
|
|
1196
|
+ 'sales.delete': '削除',
|
|
|
1197
|
+ 'sales.deleteTitle': '販売記録を削除しますか?',
|
|
|
1198
|
+ 'sales.deleteMessage': 'この操作は取り消せません。',
|
|
|
1199
|
+ 'sales.cancel': 'キャンセル',
|
|
|
1200
|
+ 'sales.pickFromGallery': 'ギャラリーから選ぶ',
|
|
|
1201
|
+ 'sales.takeMedia': '写真 / 動画を撮る',
|
|
|
1202
|
+ 'sales.save': '販売を保存',
|
|
|
1203
|
+ 'sales.untitled': '販売',
|
|
|
1204
|
+ 'sales.noField': '圃場なし',
|
|
|
1205
|
+ 'sales.noCrop': '作物なし',
|
|
|
1206
|
+ 'sales.edit': '販売を編集',
|
|
|
1207
|
+ 'sales.update': '販売を更新',
|
|
|
1208
|
+ 'costs.title': '費用記録',
|
|
|
1209
|
+ 'costs.loading': '費用を読み込み中...',
|
|
|
1210
|
+ 'costs.empty': '費用記録がまだありません。',
|
|
|
1211
|
+ 'costs.saved': '保存しました。',
|
|
|
1212
|
+ 'costs.saving': '保存中...',
|
|
|
1213
|
+ 'costs.new': '新しい費用',
|
|
|
1214
|
+ 'costs.field': '圃場',
|
|
|
1215
|
+ 'costs.crop': '作物 (任意)',
|
|
|
1216
|
+ 'costs.selectField': '圃場を選択',
|
|
|
1217
|
+ 'costs.selectCrop': '作物を選択',
|
|
|
1218
|
+ 'costs.category': 'カテゴリ',
|
|
|
1219
|
+ 'costs.category.seed': '種子',
|
|
|
1220
|
+ 'costs.category.fertilizer': '肥料',
|
|
|
1221
|
+ 'costs.category.labor': '人件費',
|
|
|
1222
|
+ 'costs.category.fuel': '燃料',
|
|
|
1223
|
+ 'costs.category.equipment': '設備',
|
|
|
1224
|
+ 'costs.category.transport': '輸送',
|
|
|
1225
|
+ 'costs.category.misc': 'その他',
|
|
|
1226
|
+ 'costs.categoryPlaceholder': '例: 種子',
|
|
|
1227
|
+ 'costs.amount': '金額',
|
|
|
1228
|
+ 'costs.amountPlaceholder': '例: 1200',
|
|
|
1229
|
+ 'costs.vendor': '仕入先',
|
|
|
1230
|
+ 'costs.vendorPlaceholder': '例: 地元の資材店',
|
|
|
1231
|
+ 'costs.date': '日付',
|
|
|
1232
|
+ 'costs.datePlaceholder': 'YYYY-MM-DD',
|
|
|
1233
|
+ 'costs.notes': 'メモ',
|
|
|
1234
|
+ 'costs.notesPlaceholder': '領収書、用途、目的...',
|
|
|
1235
|
+ 'costs.photo': '領収書写真',
|
|
|
1236
|
+ 'costs.addMedia': 'メディアを追加',
|
|
|
1237
|
+ 'costs.pickFromGallery': 'ギャラリーから選ぶ',
|
|
|
1238
|
+ 'costs.takeMedia': '写真 / 動画を撮る',
|
|
|
1239
|
+ 'costs.pickPhoto': '写真を選ぶ',
|
|
|
1240
|
+ 'costs.takePhoto': '写真を撮る',
|
|
|
1241
|
+ 'costs.noPhoto': '写真が選択されていません。',
|
|
|
1242
|
+ 'costs.fieldRequired': '圃場は必須です。',
|
|
|
1243
|
+ 'costs.amountInvalid': '金額は数値で入力してください。',
|
|
|
1244
|
+ 'costs.delete': '削除',
|
|
|
1245
|
+ 'costs.deleteTitle': '費用記録を削除しますか?',
|
|
|
1246
|
+ 'costs.deleteMessage': 'この操作は取り消せません。',
|
|
|
1247
|
+ 'costs.cancel': 'キャンセル',
|
|
|
1248
|
+ 'costs.save': '費用を保存',
|
|
|
1249
|
+ 'costs.edit': '費用を編集',
|
|
|
1250
|
+ 'costs.update': '費用を更新',
|
|
|
1251
|
+ 'costs.untitled': '費用',
|
|
|
1252
|
+ 'costs.noField': '圃場なし',
|
|
|
1253
|
+ 'costs.noCrop': '作物なし',
|
|
|
1254
|
+ 'units.kg': 'kg',
|
|
|
1255
|
+ 'units.g': 'g',
|
|
|
1256
|
+ 'units.ton': 't',
|
|
|
1257
|
+ 'units.pcs': '個',
|
|
|
1258
|
+ 'demo.field.north': '北圃場',
|
|
|
1259
|
+ 'demo.field.northNote': '壌土 · 点滴灌漑',
|
|
|
1260
|
+ 'demo.field.river': '川沿い区画',
|
|
|
1261
|
+ 'demo.field.riverNote': '水路沿いの低地',
|
|
|
1262
|
+ 'demo.field.greenhouse': '温室',
|
|
|
1263
|
+ 'demo.field.greenhouseNote': '遮光ベッド、毎日灌漑',
|
|
|
1264
|
+ 'demo.field.orchard': '果樹園区画',
|
|
|
1265
|
+ 'demo.field.orchardNote': '畝立て、東側に防風林',
|
|
|
1266
|
+ 'demo.field.terrace': '段々畑区画',
|
|
|
1267
|
+ 'demo.field.terraceNote': '段々斜面に点滴ライン',
|
|
|
1268
|
+ 'demo.crop.tomato': 'トマト',
|
|
|
1269
|
+ 'demo.crop.tomatoVariety': 'チェリー',
|
|
|
1270
|
+ 'demo.crop.rice': '米',
|
|
|
1271
|
+ 'demo.crop.riceVariety': 'ジャスミン',
|
|
|
1272
|
+ 'demo.crop.lettuce': 'レタス',
|
|
|
1273
|
+ 'demo.crop.lettuceVariety': 'バターヘッド',
|
|
|
1274
|
+ 'demo.crop.chili': '唐辛子',
|
|
|
1275
|
+ 'demo.crop.chiliVariety': 'バードアイ',
|
|
|
1276
|
+ 'demo.crop.cabbage': 'キャベツ',
|
|
|
1277
|
+ 'demo.crop.cabbageVariety': '青キャベツ',
|
|
|
1278
|
+ 'demo.observation.scoutingNote': '畝の端で初期の斑点を確認。',
|
|
|
1279
|
+ 'demo.observation.diseaseNote': '雨の後に病斑が見られました。',
|
|
|
1280
|
+ 'demo.observation.irrigationNote': '灌漑時間を夕方に調整。',
|
|
|
1281
|
+ 'demo.observation.pestNote': '新芽にアブラムシを確認。',
|
|
|
1282
|
+ 'demo.observation.nutrientNote': '下葉が淡く、葉面散布を実施。',
|
|
|
1283
|
+ 'demo.task.note': '予定通り完了。',
|
|
|
1284
|
+ 'demo.task.note2': '標準チェックリストを実施。',
|
|
|
1285
|
+ 'demo.task.note3': '機材確認と記録を完了。',
|
|
|
1286
|
+ 'demo.harvest.note1': '朝の収穫、品質良好。',
|
|
|
1287
|
+ 'demo.harvest.note2': '小雨後に収穫。',
|
|
|
1288
|
+ 'demo.harvest.note3': '市場向けにサイズ別選別。',
|
|
|
1289
|
+ 'demo.sale.buyer1': '地元市場',
|
|
|
1290
|
+ 'demo.sale.buyer2': '卸売業者',
|
|
|
1291
|
+ 'demo.sale.buyer3': 'レストラン取引先',
|
|
|
1292
|
+ 'demo.sale.note1': '当日配送。',
|
|
|
1293
|
+ 'demo.sale.note2': '全額支払い済み。',
|
|
|
1294
|
+ 'demo.sale.note3': '週次供給を依頼。',
|
|
|
1295
|
+ 'demo.cost.vendor1': '農業資材店',
|
|
|
1296
|
+ 'demo.cost.vendor2': '肥料店',
|
|
|
1297
|
+ 'demo.cost.vendor3': '作業班',
|
|
|
1298
|
+ 'demo.cost.note1': 'トマト種子とトレー。',
|
|
|
1299
|
+ 'demo.cost.note2': '水田用の元肥。',
|
|
|
1300
|
+ 'demo.cost.note3': '収穫補助(半日)。',
|
|
|
1301
|
+ 'observations.type.scouting': '観察',
|
|
|
1302
|
+ 'observations.type.pest': '害虫',
|
|
|
1303
|
+ 'observations.type.disease': '病害',
|
|
|
1304
|
+ 'observations.type.irrigation': '灌漑',
|
|
|
1305
|
+ 'observations.type.weeds': '雑草',
|
|
|
1306
|
+ 'observations.type.nutrients': '栄養',
|
|
|
1307
|
+ 'crops.title': '作物',
|
|
|
1308
|
+ 'crops.loading': '作物を読み込み中...',
|
|
|
1309
|
+ 'crops.empty': '作物がまだありません。',
|
|
|
1310
|
+ 'crops.saved': '保存しました。',
|
|
|
1311
|
+ 'crops.saving': '保存中...',
|
|
|
1312
|
+ 'crops.field': '圃場',
|
|
|
1313
|
+ 'crops.selectField': '圃場を選択',
|
|
|
1314
|
+ 'crops.name': '作物名',
|
|
|
1315
|
+ 'crops.variety': '品種',
|
|
|
1316
|
+ 'crops.planting': '定植日',
|
|
|
1317
|
+ 'crops.harvest': '収穫予定',
|
|
|
1318
|
+ 'crops.selectDate': '日付を選択',
|
|
|
1319
|
+ 'crops.namePlaceholder': '例: トマト',
|
|
|
1320
|
+ 'crops.varietyPlaceholder': '例: チェリー',
|
|
|
1321
|
+ 'crops.plantingPlaceholder': 'YYYY-MM-DD',
|
|
|
1322
|
+ 'crops.harvestPlaceholder': 'YYYY-MM-DD',
|
|
|
1323
|
+ 'crops.fieldRequired': '圃場は必須です。',
|
|
|
1324
|
+ 'crops.nameRequired': '作物名は必須です。',
|
|
|
1325
|
+ 'crops.delete': '削除',
|
|
|
1326
|
+ 'crops.deleteTitle': '作物を削除しますか?',
|
|
|
1327
|
+ 'crops.deleteMessage': 'この操作は取り消せません。',
|
|
|
1328
|
+ 'crops.noField': '圃場なし',
|
|
|
1329
|
+ 'crops.untitled': '作物',
|
|
|
1330
|
+ 'crops.plantingLabel': '定植:',
|
|
|
1331
|
+ 'crops.harvestLabel': '収穫:',
|
|
|
1332
|
+ 'crops.save': '作物を保存',
|
|
|
1333
|
+ 'crops.new': '新しい作物',
|
|
|
1334
|
+ 'crops.photo': '作物写真',
|
|
|
1335
|
+ 'crops.addMedia': 'メディアを追加',
|
|
|
1336
|
+ 'crops.pickFromGallery': 'ギャラリーから選ぶ',
|
|
|
1337
|
+ 'crops.takeMedia': '写真 / 動画を撮る',
|
|
|
1338
|
+ 'crops.pickPhoto': '写真を選ぶ',
|
|
|
1339
|
+ 'crops.takePhoto': '写真を撮る',
|
|
|
1340
|
+ 'crops.noPhoto': '写真が選択されていません。',
|
|
|
1341
|
+ 'crops.today': '今日',
|
|
|
1342
|
+ 'crops.done': '完了',
|
|
|
1343
|
+ 'crops.edit': '作物を編集',
|
|
|
1344
|
+ 'crops.update': '作物を更新',
|
|
|
1345
|
+ 'crops.cancel': 'キャンセル',
|
|
|
1346
|
+ },
|
|
838
|
1347
|
};
|
|
839
|
1348
|
|
|
|
1349
|
+export function createTranslator(language: Language) {
|
|
|
1350
|
+ return (key: string, params?: Params) => {
|
|
|
1351
|
+ const template = strings[language][key] ?? strings.en[key] ?? key;
|
|
|
1352
|
+ if (!params) return template;
|
|
|
1353
|
+ return Object.keys(params).reduce((result, paramKey) => {
|
|
|
1354
|
+ return result.replace(
|
|
|
1355
|
+ new RegExp(`{{${paramKey}}}`, 'g'),
|
|
|
1356
|
+ String(params[paramKey])
|
|
|
1357
|
+ );
|
|
|
1358
|
+ }, template);
|
|
|
1359
|
+ };
|
|
|
1360
|
+}
|
|
|
1361
|
+
|
|
840
|
1362
|
function getDeviceLanguage(): Language {
|
|
841
|
1363
|
try {
|
|
842
|
1364
|
const locale = Intl.DateTimeFormat().resolvedOptions().locale;
|
|
843
|
1365
|
if (locale.toLowerCase().startsWith('th')) return 'th';
|
|
|
1366
|
+ if (locale.toLowerCase().startsWith('ja')) return 'ja';
|
|
844
|
1367
|
} catch {
|
|
845
|
1368
|
// fall through
|
|
846
|
1369
|
}
|