暂无描述

i18n.tsx 69KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413
  1. import {
  2. createContext,
  3. useCallback,
  4. useContext,
  5. useMemo,
  6. useState,
  7. type ReactNode,
  8. } from 'react';
  9. type Language = 'en' | 'th' | 'ja';
  10. type Params = Record<string, string | number>;
  11. const strings: Record<Language, Record<string, string>> = {
  12. en: {
  13. 'common.close': 'Close',
  14. 'tabs.home': 'Home',
  15. 'tabs.explore': 'Explore',
  16. 'tabs.onnx': 'Leaf Scan',
  17. 'tabs.setup': 'Setup',
  18. 'tabs.blog': 'Blog',
  19. 'tabs.tasks': 'Tasks',
  20. 'tabs.fields': 'Fields',
  21. 'tabs.logbook': 'Logbook',
  22. 'tabs.taskHistory': 'History',
  23. 'setup.title': 'User Setup',
  24. 'setup.profile': 'Profile',
  25. 'setup.loading': 'Loading...',
  26. 'setup.loaded': 'Loaded saved profile.',
  27. 'setup.none': 'No profile yet. Fill the form and save.',
  28. 'setup.saving': 'Saving...',
  29. 'setup.saved': 'Saved locally.',
  30. 'setup.photo': 'Profile photo',
  31. 'setup.noPhoto': 'No photo selected.',
  32. 'setup.uploadPhoto': 'Upload photo',
  33. 'setup.exportTitle': 'Export data',
  34. 'setup.exportHint': 'Download your local data as a JSON file.',
  35. 'setup.exportButton': 'Export data',
  36. 'setup.exported': 'Exported data.',
  37. 'setup.exportError': 'Export failed.',
  38. 'setup.name': 'Name',
  39. 'setup.farmName': 'Farm name',
  40. 'setup.location': 'Location',
  41. 'setup.save': 'Save locally',
  42. 'setup.saveIndicator': 'Saved!',
  43. 'setup.language': 'Language',
  44. 'setup.lang.en': 'English',
  45. 'setup.lang.th': 'Thai',
  46. 'setup.lang.ja': 'Japanese',
  47. 'setup.currency': 'Default currency',
  48. 'setup.currencyPlaceholder': 'e.g. THB',
  49. 'setup.currency.thb': 'THB',
  50. 'setup.currency.usd': 'USD',
  51. 'setup.currency.eur': 'EUR',
  52. 'setup.currency.jpy': 'JPY',
  53. 'setup.demoTitle': 'Demo Data',
  54. 'setup.demoHint': 'Insert sample fields, crops, observations, and task history.',
  55. 'setup.demoButton': 'Insert demo data',
  56. 'setup.demoInserting': 'Inserting demo data...',
  57. 'setup.demoInserted': 'Demo data inserted.',
  58. 'setup.demoExists': 'Demo data already exists.',
  59. 'setup.demoError': 'Demo insert failed.',
  60. 'setup.demoClearButton': 'Clear demo data',
  61. 'setup.demoClearing': 'Clearing demo data...',
  62. 'setup.demoCleared': 'Demo data cleared.',
  63. 'setup.demoClearError': 'Clear demo failed.',
  64. 'setup.demoClearedUndo': 'Demo data cleared.',
  65. 'setup.demoUndo': 'Undo',
  66. 'setup.demoUndoDone': 'Demo data restored.',
  67. 'setup.demoUndoError': 'Undo failed.',
  68. 'onnx.title': 'Leaf Classifier',
  69. 'onnx.howTitle': 'How to use the ONNX model',
  70. 'onnx.howBody':
  71. 'This page loads the PlantVillage MobileNetV3-Small model and runs inference on a 224x224 RGB tensor. The input is normalized to 0..1 per channel.',
  72. 'onnx.sampleTitle': 'Sample code',
  73. 'onnx.testTitle': 'Test the model',
  74. 'onnx.pickImage': 'Pick image',
  75. 'onnx.runModel': 'Run model',
  76. 'onnx.status.pick': 'Pick an image to run the model.',
  77. 'onnx.status.ready': 'Ready. Tap "Run model" to classify.',
  78. 'onnx.status.preprocessing': 'Preprocessing image...',
  79. 'onnx.status.running': 'Running PlantVillage model...',
  80. 'onnx.status.done': 'Done.',
  81. 'onnx.status.nativeMissing': 'ONNX runtime not available. Use a dev build.',
  82. 'onnx.topPredictions': 'Top predictions',
  83. 'blog.title': 'Blog Posts',
  84. 'blog.loading': 'Loading posts...',
  85. 'blog.error': 'Failed to load posts.',
  86. 'blog.empty': 'No posts found.',
  87. 'blog.loadMore': 'Load more',
  88. 'blog.loadingMore': 'Loading more...',
  89. 'blog.language': 'Language',
  90. 'blog.lang.en': 'English',
  91. 'blog.lang.th': 'Thai',
  92. 'blog.lang.ja': 'Japanese',
  93. 'blog.lang.zh': 'Chinese',
  94. 'home.badge': 'Smartfarming Lite',
  95. 'home.title': 'Track fields, crops, and observations without leaving the farm.',
  96. 'home.subtitle': 'Offline-first records for daily work, photos, and crop history.',
  97. 'home.openLogbook': 'Open Logbook',
  98. 'home.todayTasks': "Today’s Tasks",
  99. 'home.quickActions': 'Quick Actions',
  100. 'home.fields': 'Fields',
  101. 'home.fieldsHint': 'Add area, notes, photos.',
  102. 'home.crops': 'Crops',
  103. 'home.cropsHint': 'Planting and harvest dates.',
  104. 'home.observations': 'Observations',
  105. 'home.observationsHint': 'Notes, severity, images.',
  106. 'home.onnx': 'Leaf Scan',
  107. 'home.onnxHint': 'Run leaf classifier.',
  108. 'home.harvests': 'Harvests',
  109. 'home.harvestsHint': 'Yield and harvest records.',
  110. 'home.sales': 'Sales',
  111. 'home.salesHint': 'Sales records and buyers.',
  112. 'home.costs': 'Costs',
  113. 'home.costsHint': 'Record expenses.',
  114. 'home.todayTitle': 'Today',
  115. 'home.todayCardTitle': 'Log your field routine',
  116. 'home.todayCardBody':
  117. 'Capture scouting notes, attach photos, and keep a clean history for the next visit.',
  118. 'home.openTasks': 'Open Tasks',
  119. 'home.taskHistory': 'Task History',
  120. 'home.learnAnalyze': 'Learn & Analyze',
  121. 'home.blogs': 'Blogs',
  122. 'home.blogsHint': 'Latest smart farming posts.',
  123. 'home.profile': 'Profile',
  124. 'home.profileHint': 'Farm info and language.',
  125. 'home.count.tasks': 'Tasks',
  126. 'home.count.history': 'History',
  127. 'tasks.title': 'Daily Tasks',
  128. 'tasks.subtitle': 'Log today’s field routine.',
  129. 'tasks.loading': 'Loading tasks...',
  130. 'tasks.saving': 'Saving...',
  131. 'tasks.saved': 'Saved.',
  132. 'tasks.empty': 'No tasks configured yet.',
  133. 'tasks.pending': 'Pending',
  134. 'tasks.done': 'Done',
  135. 'tasks.complete': 'Mark done',
  136. 'tasks.save': 'Save',
  137. 'tasks.open': 'In progress',
  138. 'tasks.undo': 'Undo',
  139. 'tasks.notePlaceholder': 'Add notes for today...',
  140. 'tasks.photo': 'Task photo',
  141. 'tasks.addMedia': 'Add media',
  142. 'tasks.pickFromGallery': 'Pick from gallery',
  143. 'tasks.takeMedia': 'Take photo / video',
  144. 'tasks.pickPhoto': 'Pick photo',
  145. 'tasks.takePhoto': 'Take photo',
  146. 'tasks.cameraDenied': 'Camera permission denied.',
  147. 'tasks.cameraError': 'Camera is not available.',
  148. 'tasks.historyTitle': 'Task History',
  149. 'tasks.historyEmpty': 'No task history yet.',
  150. 'tasks.back': 'Back to Tasks',
  151. 'tasks.default.fieldCheck': 'Field check-in',
  152. 'tasks.default.fieldCheckDesc': 'Quick field condition and notes.',
  153. 'tasks.default.scouting': 'Pest/Disease scouting',
  154. 'tasks.default.scoutingDesc': 'Inspect leaves and record severity.',
  155. 'tasks.default.sensors': 'Sensor readings',
  156. 'tasks.default.sensorsDesc': 'Log soil moisture or weather snapshot.',
  157. 'fields.title': 'Fields',
  158. 'fields.loading': 'Loading fields...',
  159. 'fields.empty': 'No fields yet.',
  160. 'fields.nameRequired': 'Field name is required.',
  161. 'fields.areaInvalid': 'Area must be a number.',
  162. 'fields.saved': 'Saved.',
  163. 'fields.saving': 'Saving...',
  164. 'fields.name': 'Field name',
  165. 'fields.area': 'Area (ha)',
  166. 'fields.areaPlaceholder': 'e.g. 1.5',
  167. 'fields.notes': 'Notes',
  168. 'fields.notesPlaceholder': 'Soil, irrigation, landmarks...',
  169. 'fields.save': 'Save field',
  170. 'fields.update': 'Update field',
  171. 'fields.cancel': 'Cancel',
  172. 'fields.edit': 'Edit',
  173. 'fields.delete': 'Delete',
  174. 'fields.deleteTitle': 'Delete field?',
  175. 'fields.deleteMessage': 'This action cannot be undone.',
  176. 'fields.new': 'New field',
  177. 'fields.unnamed': 'Unnamed field',
  178. 'fields.areaLabel': 'Area:',
  179. 'fields.photo': 'Field photo',
  180. 'fields.addMedia': 'Add media',
  181. 'fields.pickFromGallery': 'Pick from gallery',
  182. 'fields.takeMedia': 'Take photo / video',
  183. 'fields.videoSelected': 'Video selected.',
  184. 'fields.pickPhoto': 'Pick photo',
  185. 'fields.takePhoto': 'Take photo',
  186. 'fields.noPhoto': 'No photo selected.',
  187. 'fields.updatedAt': 'Updated:',
  188. 'logbook.title': 'Logbook',
  189. 'logbook.subtitle': 'Manage your core records.',
  190. 'logbook.fields': 'Fields',
  191. 'logbook.fieldsHint': 'Land area, notes, boundaries.',
  192. 'logbook.observations': 'Observations',
  193. 'logbook.observationsHint': 'Scouting notes and severity.',
  194. 'logbook.crops': 'Crops',
  195. 'logbook.cropsHint': 'Crop info by field.',
  196. 'logbook.tasks': 'Daily Tasks',
  197. 'logbook.tasksHint': 'Notes, photos, status.',
  198. 'logbook.history': 'Task History',
  199. 'logbook.historyHint': 'Completed entries by date.',
  200. 'logbook.harvests': 'Harvests',
  201. 'logbook.harvestsHint': 'Yield and harvest details.',
  202. 'logbook.sales': 'Sales',
  203. 'logbook.salesHint': 'Sales records and buyers.',
  204. 'logbook.costs': 'Costs',
  205. 'logbook.costsHint': 'Expenses and receipts.',
  206. 'observations.title': 'Observations',
  207. 'observations.loading': 'Loading observations...',
  208. 'observations.empty': 'No observations yet.',
  209. 'observations.saved': 'Saved.',
  210. 'observations.saving': 'Saving...',
  211. 'observations.field': 'Field',
  212. 'observations.crop': 'Crop',
  213. 'observations.type': 'Type',
  214. 'observations.note': 'Note',
  215. 'observations.severity': 'Severity',
  216. 'observations.severityLabel': 'Severity:',
  217. 'observations.selectField': 'Select field',
  218. 'observations.selectCrop': 'Select crop',
  219. 'observations.typePlaceholder': 'e.g. scouting',
  220. 'observations.notePlaceholder': 'What did you observe?',
  221. 'observations.severityPlaceholder': '0-10',
  222. 'observations.fieldRequired': 'Field is required.',
  223. 'observations.severityInvalid': 'Severity must be a number.',
  224. 'observations.delete': 'Delete',
  225. 'observations.noField': 'No field',
  226. 'observations.noCrop': 'No crop',
  227. 'observations.untitled': 'Observation',
  228. 'observations.save': 'Save observation',
  229. 'observations.new': 'New observation',
  230. 'observations.cancel': 'Cancel',
  231. 'observations.edit': 'Edit observation',
  232. 'observations.update': 'Update observation',
  233. 'observations.photo': 'Observation photo',
  234. 'observations.addMedia': 'Add media',
  235. 'observations.pickFromGallery': 'Pick from gallery',
  236. 'observations.takeMedia': 'Take photo / video',
  237. 'observations.pickPhoto': 'Pick photo',
  238. 'observations.takePhoto': 'Take photo',
  239. 'observations.noPhoto': 'No photo selected.',
  240. 'harvests.title': 'Harvest Records',
  241. 'harvests.loading': 'Loading harvest records...',
  242. 'harvests.empty': 'No harvest records yet.',
  243. 'harvests.saved': 'Saved.',
  244. 'harvests.saving': 'Saving...',
  245. 'harvests.new': 'New harvest',
  246. 'harvests.field': 'Field',
  247. 'harvests.crop': 'Crop',
  248. 'harvests.selectField': 'Select field',
  249. 'harvests.selectCrop': 'Select crop',
  250. 'harvests.date': 'Harvest date',
  251. 'harvests.datePlaceholder': 'YYYY-MM-DD',
  252. 'harvests.quantity': 'Quantity',
  253. 'harvests.quantityPlaceholder': 'e.g. 120',
  254. 'harvests.unit': 'Unit',
  255. 'harvests.unitPlaceholder': 'kg',
  256. 'harvests.notes': 'Notes',
  257. 'harvests.notesPlaceholder': 'Quality, weather, labor notes...',
  258. 'harvests.photo': 'Harvest photo',
  259. 'harvests.addMedia': 'Add media',
  260. 'harvests.pickFromGallery': 'Pick from gallery',
  261. 'harvests.takeMedia': 'Take photo / video',
  262. 'harvests.pickPhoto': 'Pick photo',
  263. 'harvests.takePhoto': 'Take photo',
  264. 'harvests.noPhoto': 'No photo selected.',
  265. 'harvests.fieldRequired': 'Field is required.',
  266. 'harvests.cropRequired': 'Crop is required.',
  267. 'harvests.quantityInvalid': 'Quantity must be a number.',
  268. 'harvests.delete': 'Delete',
  269. 'harvests.deleteTitle': 'Delete harvest record?',
  270. 'harvests.deleteMessage': 'This action cannot be undone.',
  271. 'harvests.cancel': 'Cancel',
  272. 'harvests.save': 'Save harvest',
  273. 'harvests.untitled': 'Harvest',
  274. 'harvests.noField': 'No field',
  275. 'harvests.noCrop': 'No crop',
  276. 'harvests.edit': 'Edit harvest',
  277. 'harvests.update': 'Update harvest',
  278. 'units.kg': 'kg',
  279. 'units.g': 'g',
  280. 'units.ton': 'ton',
  281. 'units.pcs': 'pcs',
  282. 'sales.title': 'Sales Records',
  283. 'sales.loading': 'Loading sales records...',
  284. 'sales.empty': 'No sales records yet.',
  285. 'sales.saved': 'Saved.',
  286. 'sales.saving': 'Saving...',
  287. 'sales.new': 'New sale',
  288. 'sales.field': 'Field',
  289. 'sales.crop': 'Crop',
  290. 'sales.harvest': 'Harvest (optional)',
  291. 'sales.selectField': 'Select field',
  292. 'sales.selectCrop': 'Select crop',
  293. 'sales.selectHarvest': 'Select harvest',
  294. 'sales.noHarvest': 'No harvest records',
  295. 'sales.date': 'Sale date',
  296. 'sales.datePlaceholder': 'YYYY-MM-DD',
  297. 'sales.quantity': 'Quantity',
  298. 'sales.quantityPlaceholder': 'e.g. 50',
  299. 'sales.unit': 'Unit',
  300. 'sales.unitPlaceholder': 'kg',
  301. 'sales.price': 'Price',
  302. 'sales.pricePlaceholder': 'e.g. 35',
  303. 'sales.priceLabel': 'Price:',
  304. 'sales.buyer': 'Buyer',
  305. 'sales.buyerPlaceholder': 'e.g. Local market',
  306. 'sales.notes': 'Notes',
  307. 'sales.notesPlaceholder': 'Payment, transport, quality...',
  308. 'sales.fieldRequired': 'Field is required.',
  309. 'sales.cropRequired': 'Crop is required.',
  310. 'sales.quantityInvalid': 'Quantity must be a number.',
  311. 'sales.delete': 'Delete',
  312. 'sales.deleteTitle': 'Delete sales record?',
  313. 'sales.deleteMessage': 'This action cannot be undone.',
  314. 'sales.cancel': 'Cancel',
  315. 'sales.pickFromGallery': 'Pick from gallery',
  316. 'sales.takeMedia': 'Take photo / video',
  317. 'sales.save': 'Save sale',
  318. 'sales.untitled': 'Sale',
  319. 'sales.noField': 'No field',
  320. 'sales.noCrop': 'No crop',
  321. 'sales.edit': 'Edit sale',
  322. 'sales.update': 'Update sale',
  323. 'costs.title': 'Cost Records',
  324. 'costs.loading': 'Loading costs...',
  325. 'costs.empty': 'No cost records yet.',
  326. 'costs.saved': 'Saved.',
  327. 'costs.saving': 'Saving...',
  328. 'costs.new': 'New cost',
  329. 'costs.field': 'Field',
  330. 'costs.crop': 'Crop (optional)',
  331. 'costs.selectField': 'Select field',
  332. 'costs.selectCrop': 'Select crop',
  333. 'costs.category': 'Category',
  334. 'costs.category.seed': 'Seed',
  335. 'costs.category.fertilizer': 'Fertilizer',
  336. 'costs.category.labor': 'Labor',
  337. 'costs.category.fuel': 'Fuel',
  338. 'costs.category.equipment': 'Equipment',
  339. 'costs.category.transport': 'Transport',
  340. 'costs.category.misc': 'Misc',
  341. 'costs.categoryPlaceholder': 'e.g. Seed',
  342. 'costs.amount': 'Amount',
  343. 'costs.amountPlaceholder': 'e.g. 1200',
  344. 'costs.vendor': 'Vendor',
  345. 'costs.vendorPlaceholder': 'e.g. Local supplier',
  346. 'costs.date': 'Date',
  347. 'costs.datePlaceholder': 'YYYY-MM-DD',
  348. 'costs.notes': 'Notes',
  349. 'costs.notesPlaceholder': 'Receipt, usage, purpose...',
  350. 'costs.photo': 'Receipt photo',
  351. 'costs.addMedia': 'Add media',
  352. 'costs.pickFromGallery': 'Pick from gallery',
  353. 'costs.takeMedia': 'Take photo / video',
  354. 'costs.pickPhoto': 'Pick photo',
  355. 'costs.takePhoto': 'Take photo',
  356. 'costs.noPhoto': 'No photo selected.',
  357. 'costs.fieldRequired': 'Field is required.',
  358. 'costs.amountInvalid': 'Amount must be a number.',
  359. 'costs.delete': 'Delete',
  360. 'costs.deleteTitle': 'Delete cost record?',
  361. 'costs.deleteMessage': 'This action cannot be undone.',
  362. 'costs.cancel': 'Cancel',
  363. 'costs.save': 'Save cost',
  364. 'costs.edit': 'Edit cost',
  365. 'costs.update': 'Update cost',
  366. 'costs.untitled': 'Cost',
  367. 'costs.noField': 'No field',
  368. 'costs.noCrop': 'No crop',
  369. 'demo.field.north': 'North Field',
  370. 'demo.field.northNote': 'Loamy soil · drip irrigation',
  371. 'demo.field.river': 'River Plot',
  372. 'demo.field.riverNote': 'Lowland area near canal',
  373. 'demo.field.greenhouse': 'Greenhouse',
  374. 'demo.field.greenhouseNote': 'Shaded beds, irrigation daily',
  375. 'demo.field.orchard': 'Orchard Block',
  376. 'demo.field.orchardNote': 'Raised rows, windbreak on east side',
  377. 'demo.field.terrace': 'Terrace Plot',
  378. 'demo.field.terraceNote': 'Stepped slope with drip lines',
  379. 'demo.crop.tomato': 'Tomato',
  380. 'demo.crop.tomatoVariety': 'Cherry',
  381. 'demo.crop.rice': 'Rice',
  382. 'demo.crop.riceVariety': 'Jasmine',
  383. 'demo.crop.lettuce': 'Lettuce',
  384. 'demo.crop.lettuceVariety': 'Butterhead',
  385. 'demo.crop.chili': 'Chili',
  386. 'demo.crop.chiliVariety': 'Bird’s eye',
  387. 'demo.crop.cabbage': 'Cabbage',
  388. 'demo.crop.cabbageVariety': 'Green cabbage',
  389. 'demo.observation.scoutingNote': 'Early leaf spot found on edge rows.',
  390. 'demo.observation.diseaseNote': 'Disease patches visible after rain.',
  391. 'demo.observation.irrigationNote': 'Adjusted irrigation timing to evening.',
  392. 'demo.observation.pestNote': 'Aphids spotted on new growth.',
  393. 'demo.observation.nutrientNote': 'Lower leaves pale, applied foliar feed.',
  394. 'demo.task.note': 'Completed as scheduled.',
  395. 'demo.task.note2': 'Followed standard checklist.',
  396. 'demo.task.note3': 'Checked equipment and logged readings.',
  397. 'demo.harvest.note1': 'Morning harvest, good quality.',
  398. 'demo.harvest.note2': 'Harvested after light rain.',
  399. 'demo.harvest.note3': 'Sorted by size for market.',
  400. 'demo.sale.buyer1': 'Local market',
  401. 'demo.sale.buyer2': 'Wholesale buyer',
  402. 'demo.sale.buyer3': 'Restaurant partner',
  403. 'demo.sale.note1': 'Delivered same day.',
  404. 'demo.sale.note2': 'Paid in full.',
  405. 'demo.sale.note3': 'Requested weekly supply.',
  406. 'demo.cost.vendor1': 'Agro supply',
  407. 'demo.cost.vendor2': 'Fertilizer store',
  408. 'demo.cost.vendor3': 'Labor crew',
  409. 'demo.cost.note1': 'Tomato seeds and trays.',
  410. 'demo.cost.note2': 'Base fertilizer for rice plot.',
  411. 'demo.cost.note3': 'Harvest helpers (half day).',
  412. 'observations.type.scouting': 'Scouting',
  413. 'observations.type.pest': 'Pest',
  414. 'observations.type.disease': 'Disease',
  415. 'observations.type.irrigation': 'Irrigation',
  416. 'observations.type.weeds': 'Weeds',
  417. 'observations.type.nutrients': 'Nutrients',
  418. 'crops.title': 'Crops',
  419. 'crops.loading': 'Loading crops...',
  420. 'crops.empty': 'No crops yet.',
  421. 'crops.saved': 'Saved.',
  422. 'crops.saving': 'Saving...',
  423. 'crops.field': 'Field',
  424. 'crops.selectField': 'Select field',
  425. 'crops.name': 'Crop name',
  426. 'crops.variety': 'Variety',
  427. 'crops.planting': 'Planting date',
  428. 'crops.harvest': 'Expected harvest',
  429. 'crops.selectDate': 'Select date',
  430. 'crops.namePlaceholder': 'e.g. Tomato',
  431. 'crops.varietyPlaceholder': 'e.g. Cherry',
  432. 'crops.plantingPlaceholder': 'YYYY-MM-DD',
  433. 'crops.harvestPlaceholder': 'YYYY-MM-DD',
  434. 'crops.fieldRequired': 'Field is required.',
  435. 'crops.nameRequired': 'Crop name is required.',
  436. 'crops.delete': 'Delete',
  437. 'crops.deleteTitle': 'Delete crop?',
  438. 'crops.deleteMessage': 'This action cannot be undone.',
  439. 'crops.noField': 'No field',
  440. 'crops.untitled': 'Crop',
  441. 'crops.plantingLabel': 'Planted:',
  442. 'crops.harvestLabel': 'Harvest:',
  443. 'crops.save': 'Save crop',
  444. 'crops.new': 'New crop',
  445. 'crops.photo': 'Crop photo',
  446. 'crops.addMedia': 'Add media',
  447. 'crops.pickFromGallery': 'Pick from gallery',
  448. 'crops.takeMedia': 'Take photo / video',
  449. 'crops.pickPhoto': 'Pick photo',
  450. 'crops.takePhoto': 'Take photo',
  451. 'crops.noPhoto': 'No photo selected.',
  452. 'crops.today': 'Today',
  453. 'crops.done': 'Done',
  454. 'crops.edit': 'Edit crop',
  455. 'crops.update': 'Update crop',
  456. 'crops.cancel': 'Cancel',
  457. },
  458. th: {
  459. 'common.close': 'ปิด',
  460. 'tabs.home': 'หน้าแรก',
  461. 'tabs.explore': 'สำรวจ',
  462. 'tabs.onnx': 'สแกนใบ',
  463. 'tabs.setup': 'ตั้งค่า',
  464. 'tabs.blog': 'บล็อก',
  465. 'tabs.tasks': 'งานประจำวัน',
  466. 'tabs.fields': 'แปลง',
  467. 'tabs.logbook': 'บันทึก',
  468. 'tabs.taskHistory': 'ประวัติ',
  469. 'setup.title': 'ตั้งค่าผู้ใช้',
  470. 'setup.profile': 'โปรไฟล์',
  471. 'setup.loading': 'กำลังโหลด...',
  472. 'setup.loaded': 'โหลดโปรไฟล์ที่บันทึกไว้แล้ว',
  473. 'setup.none': 'ยังไม่มีโปรไฟล์ กรอกข้อมูลแล้วกดบันทึก',
  474. 'setup.saving': 'กำลังบันทึก...',
  475. 'setup.saved': 'บันทึกไว้ในเครื่องแล้ว',
  476. 'setup.photo': 'รูปโปรไฟล์',
  477. 'setup.noPhoto': 'ยังไม่ได้เลือกรูป',
  478. 'setup.uploadPhoto': 'อัปโหลดรูป',
  479. 'setup.exportTitle': 'ส่งออกข้อมูล',
  480. 'setup.exportHint': 'ดาวน์โหลดข้อมูลในเครื่องเป็นไฟล์ JSON',
  481. 'setup.exportButton': 'ส่งออกข้อมูล',
  482. 'setup.exported': 'ส่งออกข้อมูลแล้ว',
  483. 'setup.exportError': 'ส่งออกข้อมูลไม่สำเร็จ',
  484. 'setup.name': 'ชื่อ',
  485. 'setup.farmName': 'ชื่อฟาร์ม',
  486. 'setup.location': 'ที่ตั้ง',
  487. 'setup.save': 'บันทึกในเครื่อง',
  488. 'setup.saveIndicator': 'บันทึกแล้ว',
  489. 'setup.language': 'ภาษา',
  490. 'setup.lang.en': 'English',
  491. 'setup.lang.th': 'ไทย',
  492. 'setup.lang.ja': '日本語',
  493. 'setup.currency': 'สกุลเงินเริ่มต้น',
  494. 'setup.currencyPlaceholder': 'เช่น THB',
  495. 'setup.currency.thb': 'บาท (THB)',
  496. 'setup.currency.usd': 'ดอลลาร์ (USD)',
  497. 'setup.currency.eur': 'ยูโร (EUR)',
  498. 'setup.currency.jpy': 'เยน (JPY)',
  499. 'setup.demoTitle': 'ข้อมูลตัวอย่าง',
  500. 'setup.demoHint': 'เพิ่มข้อมูลตัวอย่าง: แปลง พืช บันทึกสำรวจ และประวัติงาน',
  501. 'setup.demoButton': 'เพิ่มข้อมูลตัวอย่าง',
  502. 'setup.demoInserting': 'กำลังเพิ่มข้อมูลตัวอย่าง...',
  503. 'setup.demoInserted': 'เพิ่มข้อมูลตัวอย่างแล้ว',
  504. 'setup.demoExists': 'มีข้อมูลอยู่แล้ว',
  505. 'setup.demoError': 'เพิ่มข้อมูลไม่สำเร็จ',
  506. 'setup.demoClearButton': 'ลบข้อมูลตัวอย่าง',
  507. 'setup.demoClearing': 'กำลังลบข้อมูลตัวอย่าง...',
  508. 'setup.demoCleared': 'ลบข้อมูลตัวอย่างแล้ว',
  509. 'setup.demoClearError': 'ลบข้อมูลไม่สำเร็จ',
  510. 'setup.demoClearedUndo': 'ลบข้อมูลตัวอย่างแล้ว',
  511. 'setup.demoUndo': 'ย้อนกลับ',
  512. 'setup.demoUndoDone': 'กู้คืนข้อมูลตัวอย่างแล้ว',
  513. 'setup.demoUndoError': 'ย้อนกลับไม่สำเร็จ',
  514. 'onnx.title': 'จำแนกโรคใบพืช',
  515. 'onnx.howTitle': 'วิธีใช้โมเดล ONNX',
  516. 'onnx.howBody':
  517. 'หน้านี้โหลดโมเดล PlantVillage MobileNetV3-Small และรันอินเฟอเรนซ์ด้วยเทนเซอร์ RGB ขนาด 224x224 อินพุตถูกทำให้อยู่ในช่วง 0..1 ต่อช่องสี',
  518. 'onnx.sampleTitle': 'ตัวอย่างโค้ด',
  519. 'onnx.testTitle': 'ทดสอบโมเดล',
  520. 'onnx.pickImage': 'เลือกรูป',
  521. 'onnx.runModel': 'รันโมเดล',
  522. 'onnx.status.pick': 'เลือกรูปเพื่อรันโมเดล',
  523. 'onnx.status.ready': 'พร้อมแล้ว กด "รันโมเดล" เพื่อจำแนก',
  524. 'onnx.status.preprocessing': 'กำลังเตรียมรูป...',
  525. 'onnx.status.running': 'กำลังรันโมเดล PlantVillage...',
  526. 'onnx.status.done': 'เสร็จแล้ว',
  527. 'onnx.status.nativeMissing': 'ไม่พบ ONNX runtime โปรดใช้ dev build',
  528. 'onnx.topPredictions': 'ผลลัพธ์สูงสุด',
  529. 'blog.title': 'บทความล่าสุด',
  530. 'blog.loading': 'กำลังโหลดบทความ...',
  531. 'blog.error': 'โหลดบทความไม่สำเร็จ',
  532. 'blog.empty': 'ไม่พบบทความ',
  533. 'blog.loadMore': 'โหลดเพิ่มเติม',
  534. 'blog.loadingMore': 'กำลังโหลดเพิ่มเติม...',
  535. 'blog.language': 'ภาษา',
  536. 'blog.lang.en': 'English',
  537. 'blog.lang.th': 'ไทย',
  538. 'blog.lang.ja': 'ญี่ปุ่น',
  539. 'blog.lang.zh': 'จีน',
  540. 'home.badge': 'สมาร์ทฟาร์มมิ่ง ไลต์',
  541. 'home.title': 'ติดตามแปลง พืช และบันทึกสำรวจได้ทันทีในฟาร์ม',
  542. 'home.subtitle': 'บันทึกแบบออฟไลน์สำหรับงานประจำวัน รูปภาพ และประวัติพืช',
  543. 'home.openLogbook': 'เปิดบันทึก',
  544. 'home.todayTasks': 'งานวันนี้',
  545. 'home.quickActions': 'ทางลัด',
  546. 'home.fields': 'แปลง',
  547. 'home.fieldsHint': 'เพิ่มพื้นที่ บันทึก และรูปภาพ',
  548. 'home.crops': 'พืช',
  549. 'home.cropsHint': 'วันที่ปลูกและเก็บเกี่ยว',
  550. 'home.observations': 'บันทึกสำรวจ',
  551. 'home.observationsHint': 'บันทึก ความรุนแรง และรูปภาพ',
  552. 'home.onnx': 'สแกนใบ',
  553. 'home.onnxHint': 'รันโมเดลจำแนกใบพืช',
  554. 'home.harvests': 'เก็บเกี่ยว',
  555. 'home.harvestsHint': 'ผลผลิตและบันทึกการเก็บเกี่ยว',
  556. 'home.sales': 'ขายผลผลิต',
  557. 'home.salesHint': 'บันทึกการขายและผู้ซื้อ',
  558. 'home.costs': 'ต้นทุน',
  559. 'home.costsHint': 'บันทึกค่าใช้จ่าย',
  560. 'home.todayTitle': 'วันนี้',
  561. 'home.todayCardTitle': 'บันทึกงานประจำแปลง',
  562. 'home.todayCardBody':
  563. 'บันทึกการสำรวจ ถ่ายรูป และเก็บประวัติให้พร้อมสำหรับครั้งถัดไป',
  564. 'home.openTasks': 'เปิดงานประจำวัน',
  565. 'home.taskHistory': 'ประวัติงาน',
  566. 'home.learnAnalyze': 'เรียนรู้และวิเคราะห์',
  567. 'home.blogs': 'บล็อก',
  568. 'home.blogsHint': 'บทความสมาร์ทฟาร์มมิ่งล่าสุด',
  569. 'home.profile': 'โปรไฟล์',
  570. 'home.profileHint': 'ข้อมูลฟาร์มและภาษา',
  571. 'home.count.tasks': 'งาน',
  572. 'home.count.history': 'ประวัติ',
  573. 'tasks.title': 'งานประจำวัน',
  574. 'tasks.subtitle': 'บันทึกงานประจำวันของแปลงวันนี้',
  575. 'tasks.loading': 'กำลังโหลดงาน...',
  576. 'tasks.saving': 'กำลังบันทึก...',
  577. 'tasks.saved': 'บันทึกแล้ว',
  578. 'tasks.empty': 'ยังไม่มีงานที่ตั้งไว้',
  579. 'tasks.pending': 'รอดำเนินการ',
  580. 'tasks.done': 'เสร็จแล้ว',
  581. 'tasks.complete': 'ทำเสร็จแล้ว',
  582. 'tasks.save': 'บันทึก',
  583. 'tasks.open': 'กำลังดำเนินการ',
  584. 'tasks.undo': 'ย้อนกลับ',
  585. 'tasks.notePlaceholder': 'เพิ่มบันทึกสำหรับวันนี้...',
  586. 'tasks.photo': 'รูปงาน',
  587. 'tasks.addMedia': 'เพิ่มสื่อ',
  588. 'tasks.pickFromGallery': 'เลือกรูปจากแกลเลอรี',
  589. 'tasks.takeMedia': 'ถ่ายรูป / วิดีโอ',
  590. 'tasks.pickPhoto': 'เลือกรูป',
  591. 'tasks.takePhoto': 'ถ่ายรูป',
  592. 'tasks.cameraDenied': 'ไม่ได้รับอนุญาตให้ใช้กล้อง',
  593. 'tasks.cameraError': 'ไม่สามารถใช้งานกล้องได้',
  594. 'tasks.historyTitle': 'ประวัติงานประจำวัน',
  595. 'tasks.historyEmpty': 'ยังไม่มีประวัติงาน',
  596. 'tasks.back': 'กลับไปงานประจำวัน',
  597. 'tasks.default.fieldCheck': 'ตรวจแปลง',
  598. 'tasks.default.fieldCheckDesc': 'เช็คสภาพแปลงและบันทึกสั้น ๆ',
  599. 'tasks.default.scouting': 'สำรวจแมลง/โรค',
  600. 'tasks.default.scoutingDesc': 'ตรวจใบและบันทึกความรุนแรง',
  601. 'tasks.default.sensors': 'อ่านค่าจากเซนเซอร์',
  602. 'tasks.default.sensorsDesc': 'บันทึกความชื้นดินหรือสภาพอากาศ',
  603. 'fields.title': 'แปลง',
  604. 'fields.loading': 'กำลังโหลดแปลง...',
  605. 'fields.empty': 'ยังไม่มีแปลง',
  606. 'fields.nameRequired': 'ต้องระบุชื่อแปลง',
  607. 'fields.areaInvalid': 'พื้นที่ต้องเป็นตัวเลข',
  608. 'fields.saved': 'บันทึกแล้ว',
  609. 'fields.saving': 'กำลังบันทึก...',
  610. 'fields.name': 'ชื่อแปลง',
  611. 'fields.area': 'พื้นที่ (ไร่)',
  612. 'fields.areaPlaceholder': 'เช่น 1.5',
  613. 'fields.notes': 'บันทึก',
  614. 'fields.notesPlaceholder': 'ดิน น้ำ จุดสังเกต...',
  615. 'fields.save': 'บันทึกแปลง',
  616. 'fields.update': 'อัปเดตแปลง',
  617. 'fields.cancel': 'ยกเลิก',
  618. 'fields.edit': 'แก้ไข',
  619. 'fields.delete': 'ลบ',
  620. 'fields.deleteTitle': 'ลบแปลงนี้ไหม?',
  621. 'fields.deleteMessage': 'การลบไม่สามารถย้อนกลับได้',
  622. 'fields.new': 'เพิ่มแปลง',
  623. 'fields.unnamed': 'แปลงไม่มีชื่อ',
  624. 'fields.areaLabel': 'พื้นที่:',
  625. 'fields.photo': 'รูปแปลง',
  626. 'fields.addMedia': 'เพิ่มสื่อ',
  627. 'fields.pickFromGallery': 'เลือกรูปจากแกลเลอรี',
  628. 'fields.takeMedia': 'ถ่ายรูป / วิดีโอ',
  629. 'fields.videoSelected': 'เลือกวิดีโอแล้ว',
  630. 'fields.pickPhoto': 'เลือกรูป',
  631. 'fields.takePhoto': 'ถ่ายรูป',
  632. 'fields.noPhoto': 'ยังไม่ได้เลือกรูป',
  633. 'fields.updatedAt': 'อัปเดตเมื่อ:',
  634. 'logbook.title': 'บันทึก',
  635. 'logbook.subtitle': 'จัดการข้อมูลหลักของคุณ',
  636. 'logbook.fields': 'แปลง',
  637. 'logbook.fieldsHint': 'พื้นที่ บันทึก ขอบเขต',
  638. 'logbook.observations': 'บันทึกสำรวจ',
  639. 'logbook.observationsHint': 'บันทึกสำรวจและความรุนแรง',
  640. 'logbook.crops': 'พืช',
  641. 'logbook.cropsHint': 'ข้อมูลพืชตามแปลง',
  642. 'logbook.tasks': 'งานประจำวัน',
  643. 'logbook.tasksHint': 'บันทึก รูปภาพ สถานะ',
  644. 'logbook.history': 'ประวัติงาน',
  645. 'logbook.historyHint': 'รายการที่เสร็จแล้วตามวันที่',
  646. 'logbook.harvests': 'เก็บเกี่ยว',
  647. 'logbook.harvestsHint': 'ผลผลิตและรายละเอียดการเก็บเกี่ยว',
  648. 'logbook.sales': 'ขายผลผลิต',
  649. 'logbook.salesHint': 'บันทึกการขายและผู้ซื้อ',
  650. 'logbook.costs': 'ต้นทุน',
  651. 'logbook.costsHint': 'ค่าใช้จ่ายและใบเสร็จ',
  652. 'observations.title': 'บันทึกสำรวจ',
  653. 'observations.loading': 'กำลังโหลดบันทึก...',
  654. 'observations.empty': 'ยังไม่มีบันทึก',
  655. 'observations.saved': 'บันทึกแล้ว',
  656. 'observations.saving': 'กำลังบันทึก...',
  657. 'observations.field': 'แปลง',
  658. 'observations.crop': 'พืช',
  659. 'observations.type': 'ประเภท',
  660. 'observations.note': 'บันทึก',
  661. 'observations.severity': 'ความรุนแรง',
  662. 'observations.severityLabel': 'ความรุนแรง:',
  663. 'observations.selectField': 'เลือกแปลง',
  664. 'observations.selectCrop': 'เลือกพืช',
  665. 'observations.typePlaceholder': 'เช่น สำรวจโรค',
  666. 'observations.notePlaceholder': 'สังเกตอะไรบ้าง?',
  667. 'observations.severityPlaceholder': '0-10',
  668. 'observations.fieldRequired': 'ต้องเลือกแปลง',
  669. 'observations.severityInvalid': 'ความรุนแรงต้องเป็นตัวเลข',
  670. 'observations.delete': 'ลบ',
  671. 'observations.noField': 'ไม่มีแปลง',
  672. 'observations.noCrop': 'ไม่มีพืช',
  673. 'observations.untitled': 'บันทึกสำรวจ',
  674. 'observations.save': 'บันทึกข้อมูล',
  675. 'observations.new': 'เพิ่มบันทึก',
  676. 'observations.cancel': 'ยกเลิก',
  677. 'observations.edit': 'แก้ไขบันทึก',
  678. 'observations.update': 'อัปเดตบันทึก',
  679. 'observations.photo': 'รูปประกอบ',
  680. 'observations.addMedia': 'เพิ่มสื่อ',
  681. 'observations.pickFromGallery': 'เลือกรูปจากแกลเลอรี',
  682. 'observations.takeMedia': 'ถ่ายรูป / วิดีโอ',
  683. 'observations.pickPhoto': 'เลือกรูป',
  684. 'observations.takePhoto': 'ถ่ายรูป',
  685. 'observations.noPhoto': 'ยังไม่ได้เลือกรูป',
  686. 'harvests.title': 'บันทึกการเก็บเกี่ยว',
  687. 'harvests.loading': 'กำลังโหลดการเก็บเกี่ยว...',
  688. 'harvests.empty': 'ยังไม่มีบันทึกการเก็บเกี่ยว',
  689. 'harvests.saved': 'บันทึกแล้ว',
  690. 'harvests.saving': 'กำลังบันทึก...',
  691. 'harvests.new': 'เพิ่มการเก็บเกี่ยว',
  692. 'harvests.field': 'แปลง',
  693. 'harvests.crop': 'พืช',
  694. 'harvests.selectField': 'เลือกแปลง',
  695. 'harvests.selectCrop': 'เลือกพืช',
  696. 'harvests.date': 'วันที่เก็บเกี่ยว',
  697. 'harvests.datePlaceholder': 'YYYY-MM-DD',
  698. 'harvests.quantity': 'ปริมาณ',
  699. 'harvests.quantityPlaceholder': 'เช่น 120',
  700. 'harvests.unit': 'หน่วย',
  701. 'harvests.unitPlaceholder': 'กก.',
  702. 'harvests.notes': 'บันทึก',
  703. 'harvests.notesPlaceholder': 'คุณภาพ สภาพอากาศ แรงงาน...',
  704. 'harvests.photo': 'รูปการเก็บเกี่ยว',
  705. 'harvests.addMedia': 'เพิ่มสื่อ',
  706. 'harvests.pickFromGallery': 'เลือกรูปจากแกลเลอรี',
  707. 'harvests.takeMedia': 'ถ่ายรูป / วิดีโอ',
  708. 'harvests.pickPhoto': 'เลือกรูป',
  709. 'harvests.takePhoto': 'ถ่ายรูป',
  710. 'harvests.noPhoto': 'ยังไม่ได้เลือกรูป',
  711. 'harvests.fieldRequired': 'ต้องเลือกแปลง',
  712. 'harvests.cropRequired': 'ต้องเลือกพืช',
  713. 'harvests.quantityInvalid': 'ปริมาณต้องเป็นตัวเลข',
  714. 'harvests.delete': 'ลบ',
  715. 'harvests.deleteTitle': 'ลบบันทึกการเก็บเกี่ยว?',
  716. 'harvests.deleteMessage': 'การลบไม่สามารถย้อนกลับได้',
  717. 'harvests.cancel': 'ยกเลิก',
  718. 'harvests.save': 'บันทึกการเก็บเกี่ยว',
  719. 'harvests.untitled': 'เก็บเกี่ยว',
  720. 'harvests.noField': 'ไม่มีแปลง',
  721. 'harvests.noCrop': 'ไม่มีพืช',
  722. 'harvests.edit': 'แก้ไขการเก็บเกี่ยว',
  723. 'harvests.update': 'อัปเดตการเก็บเกี่ยว',
  724. 'sales.title': 'บันทึกการขาย',
  725. 'sales.loading': 'กำลังโหลดการขาย...',
  726. 'sales.empty': 'ยังไม่มีบันทึกการขาย',
  727. 'sales.saved': 'บันทึกแล้ว',
  728. 'sales.saving': 'กำลังบันทึก...',
  729. 'sales.new': 'เพิ่มการขาย',
  730. 'sales.field': 'แปลง',
  731. 'sales.crop': 'พืช',
  732. 'sales.harvest': 'เก็บเกี่ยว (ไม่บังคับ)',
  733. 'sales.selectField': 'เลือกแปลง',
  734. 'sales.selectCrop': 'เลือกพืช',
  735. 'sales.selectHarvest': 'เลือกการเก็บเกี่ยว',
  736. 'sales.noHarvest': 'ยังไม่มีการเก็บเกี่ยว',
  737. 'sales.date': 'วันที่ขาย',
  738. 'sales.datePlaceholder': 'YYYY-MM-DD',
  739. 'sales.quantity': 'ปริมาณ',
  740. 'sales.quantityPlaceholder': 'เช่น 50',
  741. 'sales.unit': 'หน่วย',
  742. 'sales.unitPlaceholder': 'กก.',
  743. 'sales.price': 'ราคา',
  744. 'sales.pricePlaceholder': 'เช่น 35',
  745. 'sales.priceLabel': 'ราคา:',
  746. 'sales.buyer': 'ผู้ซื้อ',
  747. 'sales.buyerPlaceholder': 'เช่น ตลาดท้องถิ่น',
  748. 'sales.notes': 'บันทึก',
  749. 'sales.notesPlaceholder': 'การชำระเงิน ขนส่ง คุณภาพ...',
  750. 'sales.fieldRequired': 'ต้องเลือกแปลง',
  751. 'sales.cropRequired': 'ต้องเลือกพืช',
  752. 'sales.quantityInvalid': 'ปริมาณต้องเป็นตัวเลข',
  753. 'sales.delete': 'ลบ',
  754. 'sales.deleteTitle': 'ลบบันทึกการขาย?',
  755. 'sales.deleteMessage': 'การลบไม่สามารถย้อนกลับได้',
  756. 'sales.cancel': 'ยกเลิก',
  757. 'sales.pickFromGallery': 'เลือกรูปจากแกลเลอรี',
  758. 'sales.takeMedia': 'ถ่ายรูป / วิดีโอ',
  759. 'sales.save': 'บันทึกการขาย',
  760. 'sales.untitled': 'การขาย',
  761. 'sales.noField': 'ไม่มีแปลง',
  762. 'sales.noCrop': 'ไม่มีพืช',
  763. 'sales.edit': 'แก้ไขการขาย',
  764. 'sales.update': 'อัปเดตการขาย',
  765. 'costs.title': 'บันทึกต้นทุน',
  766. 'costs.loading': 'กำลังโหลดต้นทุน...',
  767. 'costs.empty': 'ยังไม่มีบันทึกต้นทุน',
  768. 'costs.saved': 'บันทึกแล้ว',
  769. 'costs.saving': 'กำลังบันทึก...',
  770. 'costs.new': 'เพิ่มต้นทุน',
  771. 'costs.field': 'แปลง',
  772. 'costs.crop': 'พืช (ไม่บังคับ)',
  773. 'costs.selectField': 'เลือกแปลง',
  774. 'costs.selectCrop': 'เลือกพืช',
  775. 'costs.category': 'หมวดหมู่',
  776. 'costs.category.seed': 'เมล็ดพันธุ์',
  777. 'costs.category.fertilizer': 'ปุ๋ย',
  778. 'costs.category.labor': 'แรงงาน',
  779. 'costs.category.fuel': 'เชื้อเพลิง',
  780. 'costs.category.equipment': 'อุปกรณ์',
  781. 'costs.category.transport': 'ขนส่ง',
  782. 'costs.category.misc': 'อื่น ๆ',
  783. 'costs.categoryPlaceholder': 'เช่น เมล็ดพันธุ์',
  784. 'costs.amount': 'จำนวนเงิน',
  785. 'costs.amountPlaceholder': 'เช่น 1200',
  786. 'costs.vendor': 'ผู้ขาย',
  787. 'costs.vendorPlaceholder': 'เช่น ร้านวัสดุเกษตร',
  788. 'costs.date': 'วันที่',
  789. 'costs.datePlaceholder': 'YYYY-MM-DD',
  790. 'costs.notes': 'บันทึก',
  791. 'costs.notesPlaceholder': 'ใบเสร็จ การใช้งาน วัตถุประสงค์...',
  792. 'costs.photo': 'รูปใบเสร็จ',
  793. 'costs.addMedia': 'เพิ่มสื่อ',
  794. 'costs.pickFromGallery': 'เลือกรูปจากแกลเลอรี',
  795. 'costs.takeMedia': 'ถ่ายรูป / วิดีโอ',
  796. 'costs.pickPhoto': 'เลือกรูป',
  797. 'costs.takePhoto': 'ถ่ายรูป',
  798. 'costs.noPhoto': 'ยังไม่ได้เลือกรูป',
  799. 'costs.fieldRequired': 'ต้องเลือกแปลง',
  800. 'costs.amountInvalid': 'จำนวนเงินต้องเป็นตัวเลข',
  801. 'costs.delete': 'ลบ',
  802. 'costs.deleteTitle': 'ลบบันทึกต้นทุน?',
  803. 'costs.deleteMessage': 'การลบไม่สามารถย้อนกลับได้',
  804. 'costs.cancel': 'ยกเลิก',
  805. 'costs.save': 'บันทึกต้นทุน',
  806. 'costs.edit': 'แก้ไขต้นทุน',
  807. 'costs.update': 'อัปเดตต้นทุน',
  808. 'costs.untitled': 'ต้นทุน',
  809. 'costs.noField': 'ไม่มีแปลง',
  810. 'costs.noCrop': 'ไม่มีพืช',
  811. 'demo.field.north': 'แปลงเหนือ',
  812. 'demo.field.northNote': 'ดินร่วน · น้ำหยด',
  813. 'demo.field.river': 'แปลงริมน้ำ',
  814. 'demo.field.riverNote': 'พื้นที่ลุ่มใกล้คลอง',
  815. 'demo.field.greenhouse': 'โรงเรือน',
  816. 'demo.field.greenhouseNote': 'แปลงในร่ม รดน้ำทุกวัน',
  817. 'demo.field.orchard': 'แปลงสวนผลไม้',
  818. 'demo.field.orchardNote': 'ยกร่องและมีแนวกันลมด้านตะวันออก',
  819. 'demo.field.terrace': 'แปลงขั้นบันได',
  820. 'demo.field.terraceNote': 'พื้นที่ลาดชันแบ่งขั้น พร้อมน้ำหยด',
  821. 'demo.crop.tomato': 'มะเขือเทศ',
  822. 'demo.crop.tomatoVariety': 'เชอรี่',
  823. 'demo.crop.rice': 'ข้าว',
  824. 'demo.crop.riceVariety': 'หอมมะลิ',
  825. 'demo.crop.lettuce': 'ผักกาดหอม',
  826. 'demo.crop.lettuceVariety': 'บัตเตอร์เฮด',
  827. 'demo.crop.chili': 'พริก',
  828. 'demo.crop.chiliVariety': 'พริกขี้หนู',
  829. 'demo.crop.cabbage': 'กะหล่ำปลี',
  830. 'demo.crop.cabbageVariety': 'กะหล่ำปลีเขียว',
  831. 'demo.observation.scoutingNote': 'พบบางส่วนใบเป็นจุดเริ่มต้นตามขอบแปลง',
  832. 'demo.observation.diseaseNote': 'พบรอยโรคหลังฝนตก',
  833. 'demo.observation.irrigationNote': 'ปรับเวลารดน้ำเป็นช่วงเย็น',
  834. 'demo.observation.pestNote': 'พบเพลี้ยอ่อนตามยอดอ่อน',
  835. 'demo.observation.nutrientNote': 'ใบล่างซีด ให้ปุ๋ยทางใบเพิ่ม',
  836. 'demo.task.note': 'ทำงานเสร็จตามแผน',
  837. 'demo.task.note2': 'ทำตามเช็กลิสต์มาตรฐาน',
  838. 'demo.task.note3': 'ตรวจอุปกรณ์และบันทึกค่าแล้ว',
  839. 'demo.harvest.note1': 'เก็บช่วงเช้า คุณภาพดี',
  840. 'demo.harvest.note2': 'เก็บหลังฝนตกเล็กน้อย',
  841. 'demo.harvest.note3': 'คัดขนาดเพื่อขาย',
  842. 'demo.sale.buyer1': 'ตลาดท้องถิ่น',
  843. 'demo.sale.buyer2': 'ผู้ซื้อส่ง',
  844. 'demo.sale.buyer3': 'คู่ค้าร้านอาหาร',
  845. 'demo.sale.note1': 'ส่งของในวันเดียวกัน',
  846. 'demo.sale.note2': 'ชำระเงินครบถ้วน',
  847. 'demo.sale.note3': 'ขอสั่งประจำทุกสัปดาห์',
  848. 'demo.cost.vendor1': 'ร้านวัสดุเกษตร',
  849. 'demo.cost.vendor2': 'ร้านปุ๋ย',
  850. 'demo.cost.vendor3': 'ทีมแรงงาน',
  851. 'demo.cost.note1': 'เมล็ดมะเขือเทศและถาดเพาะ',
  852. 'demo.cost.note2': 'ปุ๋ยรองพื้นแปลงข้าว',
  853. 'demo.cost.note3': 'แรงงานช่วยเก็บเกี่ยว (ครึ่งวัน)',
  854. 'observations.type.scouting': 'สำรวจ',
  855. 'observations.type.pest': 'แมลง',
  856. 'observations.type.disease': 'โรค',
  857. 'observations.type.irrigation': 'ให้น้ำ',
  858. 'observations.type.weeds': 'วัชพืช',
  859. 'observations.type.nutrients': 'ธาตุอาหาร',
  860. 'crops.title': 'พืช',
  861. 'crops.loading': 'กำลังโหลดพืช...',
  862. 'crops.empty': 'ยังไม่มีพืช',
  863. 'crops.saved': 'บันทึกแล้ว',
  864. 'crops.saving': 'กำลังบันทึก...',
  865. 'crops.field': 'แปลง',
  866. 'crops.selectField': 'เลือกแปลง',
  867. 'crops.name': 'ชื่อพืช',
  868. 'crops.variety': 'สายพันธุ์',
  869. 'crops.planting': 'วันที่ปลูก',
  870. 'crops.harvest': 'คาดว่าจะเก็บเกี่ยว',
  871. 'crops.selectDate': 'เลือกวันที่',
  872. 'crops.namePlaceholder': 'เช่น มะเขือเทศ',
  873. 'crops.varietyPlaceholder': 'เช่น เชอรี่',
  874. 'crops.plantingPlaceholder': 'YYYY-MM-DD',
  875. 'crops.harvestPlaceholder': 'YYYY-MM-DD',
  876. 'crops.fieldRequired': 'ต้องเลือกแปลง',
  877. 'crops.nameRequired': 'ต้องกรอกชื่อพืช',
  878. 'crops.delete': 'ลบ',
  879. 'crops.deleteTitle': 'ลบพืชนี้ไหม?',
  880. 'crops.deleteMessage': 'การลบไม่สามารถย้อนกลับได้',
  881. 'crops.noField': 'ไม่มีแปลง',
  882. 'crops.untitled': 'พืช',
  883. 'crops.plantingLabel': 'ปลูก:',
  884. 'crops.harvestLabel': 'เก็บเกี่ยว:',
  885. 'crops.save': 'บันทึกพืช',
  886. 'crops.new': 'เพิ่มพืช',
  887. 'crops.photo': 'รูปพืช',
  888. 'crops.addMedia': 'เพิ่มสื่อ',
  889. 'crops.pickFromGallery': 'เลือกรูปจากแกลเลอรี',
  890. 'crops.takeMedia': 'ถ่ายรูป / วิดีโอ',
  891. 'crops.pickPhoto': 'เลือกรูป',
  892. 'crops.takePhoto': 'ถ่ายรูป',
  893. 'crops.noPhoto': 'ยังไม่ได้เลือกรูป',
  894. 'crops.today': 'วันนี้',
  895. 'crops.done': 'เสร็จ',
  896. 'crops.edit': 'แก้ไขพืช',
  897. 'crops.update': 'อัปเดตพืช',
  898. 'crops.cancel': 'ยกเลิก',
  899. },
  900. ja: {
  901. 'common.close': '閉じる',
  902. 'tabs.home': 'ホーム',
  903. 'tabs.explore': '探索',
  904. 'tabs.onnx': '葉スキャン',
  905. 'tabs.setup': '設定',
  906. 'tabs.blog': 'ブログ',
  907. 'tabs.tasks': '日次タスク',
  908. 'tabs.fields': '圃場',
  909. 'tabs.logbook': 'ログブック',
  910. 'tabs.taskHistory': '履歴',
  911. 'setup.title': 'ユーザー設定',
  912. 'setup.profile': 'プロフィール',
  913. 'setup.loading': '読み込み中...',
  914. 'setup.loaded': '保存したプロフィールを読み込みました。',
  915. 'setup.none': 'プロフィールがまだありません。入力して保存してください。',
  916. 'setup.saving': '保存中...',
  917. 'setup.saved': 'ローカルに保存しました。',
  918. 'setup.photo': 'プロフィール写真',
  919. 'setup.noPhoto': '写真が選択されていません。',
  920. 'setup.uploadPhoto': '写真をアップロード',
  921. 'setup.exportTitle': 'データを書き出し',
  922. 'setup.exportHint': 'ローカルデータをJSONとしてダウンロードします。',
  923. 'setup.exportButton': 'データを書き出し',
  924. 'setup.exported': 'データを書き出しました。',
  925. 'setup.exportError': '書き出しに失敗しました。',
  926. 'setup.name': '名前',
  927. 'setup.farmName': '農場名',
  928. 'setup.location': '所在地',
  929. 'setup.save': 'ローカルに保存',
  930. 'setup.saveIndicator': '保存しました!',
  931. 'setup.language': '言語',
  932. 'setup.lang.en': 'English',
  933. 'setup.lang.th': 'ไทย',
  934. 'setup.lang.ja': '日本語',
  935. 'setup.currency': '既定の通貨',
  936. 'setup.currencyPlaceholder': '例: JPY',
  937. 'setup.currency.thb': 'THB',
  938. 'setup.currency.usd': 'USD',
  939. 'setup.currency.eur': 'EUR',
  940. 'setup.currency.jpy': 'JPY',
  941. 'setup.demoTitle': 'デモデータ',
  942. 'setup.demoHint': 'サンプルの圃場、作物、観察、履歴を挿入します。',
  943. 'setup.demoButton': 'デモデータを挿入',
  944. 'setup.demoInserting': 'デモデータを挿入中...',
  945. 'setup.demoInserted': 'デモデータを挿入しました。',
  946. 'setup.demoExists': 'デモデータは既にあります。',
  947. 'setup.demoError': 'デモデータの挿入に失敗しました。',
  948. 'setup.demoClearButton': 'デモデータを削除',
  949. 'setup.demoClearing': 'デモデータを削除中...',
  950. 'setup.demoCleared': 'デモデータを削除しました。',
  951. 'setup.demoClearError': 'デモデータの削除に失敗しました。',
  952. 'setup.demoClearedUndo': 'デモデータを削除しました。',
  953. 'setup.demoUndo': '元に戻す',
  954. 'setup.demoUndoDone': 'デモデータを復元しました。',
  955. 'setup.demoUndoError': '元に戻せませんでした。',
  956. 'onnx.title': '葉の分類',
  957. 'onnx.howTitle': 'ONNXモデルの使い方',
  958. 'onnx.howBody':
  959. 'このページはPlantVillage MobileNetV3-Smallモデルを読み込み、224x224のRGBテンソルで推論します。入力は各チャンネル0..1に正規化されます。',
  960. 'onnx.sampleTitle': 'サンプルコード',
  961. 'onnx.testTitle': 'モデルをテスト',
  962. 'onnx.pickImage': '画像を選ぶ',
  963. 'onnx.runModel': 'モデルを実行',
  964. 'onnx.status.pick': '画像を選択してモデルを実行します。',
  965. 'onnx.status.ready': '準備完了。「モデルを実行」をタップしてください。',
  966. 'onnx.status.preprocessing': '画像を前処理中...',
  967. 'onnx.status.running': 'PlantVillageモデルを実行中...',
  968. 'onnx.status.done': '完了。',
  969. 'onnx.status.nativeMissing': 'ONNX runtimeが利用できません。dev buildを使用してください。',
  970. 'onnx.topPredictions': '上位の予測',
  971. 'blog.title': 'ブログ記事',
  972. 'blog.loading': '記事を読み込み中...',
  973. 'blog.error': '記事の読み込みに失敗しました。',
  974. 'blog.empty': '記事がありません。',
  975. 'blog.loadMore': 'さらに読み込む',
  976. 'blog.loadingMore': 'さらに読み込み中...',
  977. 'blog.language': '言語',
  978. 'blog.lang.en': 'English',
  979. 'blog.lang.th': 'ไทย',
  980. 'blog.lang.ja': '日本語',
  981. 'blog.lang.zh': '中文',
  982. 'home.badge': 'Smartfarming Lite',
  983. 'home.title': '圃場・作物・観察を、農場から離れずに記録。',
  984. 'home.subtitle': '日々の作業、写真、作物履歴をオフラインで管理。',
  985. 'home.openLogbook': 'ログブックを開く',
  986. 'home.todayTasks': '今日のタスク',
  987. 'home.quickActions': 'クイック操作',
  988. 'home.fields': '圃場',
  989. 'home.fieldsHint': '面積、メモ、写真を追加。',
  990. 'home.crops': '作物',
  991. 'home.cropsHint': '定植日と収穫予定。',
  992. 'home.observations': '観察',
  993. 'home.observationsHint': 'メモ、深刻度、画像。',
  994. 'home.onnx': '葉スキャン',
  995. 'home.onnxHint': '葉の分類を実行。',
  996. 'home.harvests': '収穫',
  997. 'home.harvestsHint': '収量と収穫記録。',
  998. 'home.sales': '販売',
  999. 'home.salesHint': '販売記録と買い手。',
  1000. 'home.costs': 'コスト',
  1001. 'home.costsHint': '支出を記録。',
  1002. 'home.todayTitle': '今日',
  1003. 'home.todayCardTitle': '圃場作業を記録',
  1004. 'home.todayCardBody': '観察メモを残し、写真を添付して次回のための履歴を整理。',
  1005. 'home.openTasks': 'タスクを開く',
  1006. 'home.taskHistory': 'タスク履歴',
  1007. 'home.learnAnalyze': '学ぶ・分析する',
  1008. 'home.blogs': 'ブログ',
  1009. 'home.blogsHint': 'スマート農業の最新記事。',
  1010. 'home.profile': 'プロフィール',
  1011. 'home.profileHint': '農場情報と言語設定。',
  1012. 'home.count.tasks': 'タスク',
  1013. 'home.count.history': '履歴',
  1014. 'tasks.title': '日次タスク',
  1015. 'tasks.subtitle': '今日の圃場作業を記録。',
  1016. 'tasks.loading': 'タスクを読み込み中...',
  1017. 'tasks.saving': '保存中...',
  1018. 'tasks.saved': '保存しました。',
  1019. 'tasks.empty': 'タスクがまだありません。',
  1020. 'tasks.pending': '未完了',
  1021. 'tasks.done': '完了',
  1022. 'tasks.complete': '完了にする',
  1023. 'tasks.save': '保存',
  1024. 'tasks.open': '進行中',
  1025. 'tasks.undo': '元に戻す',
  1026. 'tasks.notePlaceholder': '今日のメモを追加...',
  1027. 'tasks.photo': 'タスク写真',
  1028. 'tasks.addMedia': 'メディアを追加',
  1029. 'tasks.pickFromGallery': 'ギャラリーから選ぶ',
  1030. 'tasks.takeMedia': '写真 / 動画を撮る',
  1031. 'tasks.pickPhoto': '写真を選ぶ',
  1032. 'tasks.takePhoto': '写真を撮る',
  1033. 'tasks.cameraDenied': 'カメラの権限がありません。',
  1034. 'tasks.cameraError': 'カメラが利用できません。',
  1035. 'tasks.historyTitle': 'タスク履歴',
  1036. 'tasks.historyEmpty': 'タスク履歴がまだありません。',
  1037. 'tasks.back': 'タスクに戻る',
  1038. 'tasks.default.fieldCheck': '圃場チェック',
  1039. 'tasks.default.fieldCheckDesc': '圃場の状態とメモを簡単に記録。',
  1040. 'tasks.default.scouting': '病害虫の確認',
  1041. 'tasks.default.scoutingDesc': '葉を確認して深刻度を記録。',
  1042. 'tasks.default.sensors': 'センサー計測',
  1043. 'tasks.default.sensorsDesc': '土壌水分や天候の記録。',
  1044. 'fields.title': '圃場',
  1045. 'fields.loading': '圃場を読み込み中...',
  1046. 'fields.empty': '圃場がまだありません。',
  1047. 'fields.nameRequired': '圃場名は必須です。',
  1048. 'fields.areaInvalid': '面積は数値で入力してください。',
  1049. 'fields.saved': '保存しました。',
  1050. 'fields.saving': '保存中...',
  1051. 'fields.name': '圃場名',
  1052. 'fields.area': '面積 (ha)',
  1053. 'fields.areaPlaceholder': '例: 1.5',
  1054. 'fields.notes': 'メモ',
  1055. 'fields.notesPlaceholder': '土壌、灌漑、目印など...',
  1056. 'fields.save': '圃場を保存',
  1057. 'fields.update': '圃場を更新',
  1058. 'fields.cancel': 'キャンセル',
  1059. 'fields.edit': '編集',
  1060. 'fields.delete': '削除',
  1061. 'fields.deleteTitle': '圃場を削除しますか?',
  1062. 'fields.deleteMessage': 'この操作は取り消せません。',
  1063. 'fields.new': '新しい圃場',
  1064. 'fields.unnamed': '無名の圃場',
  1065. 'fields.areaLabel': '面積:',
  1066. 'fields.photo': '圃場写真',
  1067. 'fields.addMedia': 'メディアを追加',
  1068. 'fields.pickFromGallery': 'ギャラリーから選ぶ',
  1069. 'fields.takeMedia': '写真 / 動画を撮る',
  1070. 'fields.videoSelected': '動画を選択しました。',
  1071. 'fields.pickPhoto': '写真を選ぶ',
  1072. 'fields.takePhoto': '写真を撮る',
  1073. 'fields.noPhoto': '写真が選択されていません。',
  1074. 'fields.updatedAt': '更新:',
  1075. 'logbook.title': 'ログブック',
  1076. 'logbook.subtitle': '主要データを管理。',
  1077. 'logbook.fields': '圃場',
  1078. 'logbook.fieldsHint': '面積、メモ、境界。',
  1079. 'logbook.observations': '観察',
  1080. 'logbook.observationsHint': '観察メモと深刻度。',
  1081. 'logbook.crops': '作物',
  1082. 'logbook.cropsHint': '圃場ごとの作物情報。',
  1083. 'logbook.tasks': '日次タスク',
  1084. 'logbook.tasksHint': 'メモ、写真、状態。',
  1085. 'logbook.history': 'タスク履歴',
  1086. 'logbook.historyHint': '日付別の完了記録。',
  1087. 'logbook.harvests': '収穫',
  1088. 'logbook.harvestsHint': '収量と収穫の詳細。',
  1089. 'logbook.sales': '販売',
  1090. 'logbook.salesHint': '販売記録と買い手。',
  1091. 'logbook.costs': 'コスト',
  1092. 'logbook.costsHint': '支出と領収書。',
  1093. 'observations.title': '観察',
  1094. 'observations.loading': '観察を読み込み中...',
  1095. 'observations.empty': '観察がまだありません。',
  1096. 'observations.saved': '保存しました。',
  1097. 'observations.saving': '保存中...',
  1098. 'observations.field': '圃場',
  1099. 'observations.crop': '作物',
  1100. 'observations.type': '種類',
  1101. 'observations.note': 'メモ',
  1102. 'observations.severity': '深刻度',
  1103. 'observations.severityLabel': '深刻度:',
  1104. 'observations.selectField': '圃場を選択',
  1105. 'observations.selectCrop': '作物を選択',
  1106. 'observations.typePlaceholder': '例: 観察',
  1107. 'observations.notePlaceholder': '観察内容を入力してください。',
  1108. 'observations.severityPlaceholder': '0-10',
  1109. 'observations.fieldRequired': '圃場は必須です。',
  1110. 'observations.severityInvalid': '深刻度は数値で入力してください。',
  1111. 'observations.delete': '削除',
  1112. 'observations.noField': '圃場なし',
  1113. 'observations.noCrop': '作物なし',
  1114. 'observations.untitled': '観察',
  1115. 'observations.save': '観察を保存',
  1116. 'observations.new': '新しい観察',
  1117. 'observations.cancel': 'キャンセル',
  1118. 'observations.edit': '観察を編集',
  1119. 'observations.update': '観察を更新',
  1120. 'observations.photo': '観察写真',
  1121. 'observations.addMedia': 'メディアを追加',
  1122. 'observations.pickFromGallery': 'ギャラリーから選ぶ',
  1123. 'observations.takeMedia': '写真 / 動画を撮る',
  1124. 'observations.pickPhoto': '写真を選ぶ',
  1125. 'observations.takePhoto': '写真を撮る',
  1126. 'observations.noPhoto': '写真が選択されていません。',
  1127. 'harvests.title': '収穫記録',
  1128. 'harvests.loading': '収穫記録を読み込み中...',
  1129. 'harvests.empty': '収穫記録がまだありません。',
  1130. 'harvests.saved': '保存しました。',
  1131. 'harvests.saving': '保存中...',
  1132. 'harvests.new': '新しい収穫',
  1133. 'harvests.field': '圃場',
  1134. 'harvests.crop': '作物',
  1135. 'harvests.selectField': '圃場を選択',
  1136. 'harvests.selectCrop': '作物を選択',
  1137. 'harvests.date': '収穫日',
  1138. 'harvests.datePlaceholder': 'YYYY-MM-DD',
  1139. 'harvests.quantity': '数量',
  1140. 'harvests.quantityPlaceholder': '例: 120',
  1141. 'harvests.unit': '単位',
  1142. 'harvests.unitPlaceholder': 'kg',
  1143. 'harvests.notes': 'メモ',
  1144. 'harvests.notesPlaceholder': '品質、天候、人員メモ...',
  1145. 'harvests.photo': '収穫写真',
  1146. 'harvests.addMedia': 'メディアを追加',
  1147. 'harvests.pickFromGallery': 'ギャラリーから選ぶ',
  1148. 'harvests.takeMedia': '写真 / 動画を撮る',
  1149. 'harvests.pickPhoto': '写真を選ぶ',
  1150. 'harvests.takePhoto': '写真を撮る',
  1151. 'harvests.noPhoto': '写真が選択されていません。',
  1152. 'harvests.fieldRequired': '圃場は必須です。',
  1153. 'harvests.cropRequired': '作物は必須です。',
  1154. 'harvests.quantityInvalid': '数量は数値で入力してください。',
  1155. 'harvests.delete': '削除',
  1156. 'harvests.deleteTitle': '収穫記録を削除しますか?',
  1157. 'harvests.deleteMessage': 'この操作は取り消せません。',
  1158. 'harvests.cancel': 'キャンセル',
  1159. 'harvests.save': '収穫を保存',
  1160. 'harvests.untitled': '収穫',
  1161. 'harvests.noField': '圃場なし',
  1162. 'harvests.noCrop': '作物なし',
  1163. 'harvests.edit': '収穫を編集',
  1164. 'harvests.update': '収穫を更新',
  1165. 'sales.title': '販売記録',
  1166. 'sales.loading': '販売記録を読み込み中...',
  1167. 'sales.empty': '販売記録がまだありません。',
  1168. 'sales.saved': '保存しました。',
  1169. 'sales.saving': '保存中...',
  1170. 'sales.new': '新しい販売',
  1171. 'sales.field': '圃場',
  1172. 'sales.crop': '作物',
  1173. 'sales.harvest': '収穫 (任意)',
  1174. 'sales.selectField': '圃場を選択',
  1175. 'sales.selectCrop': '作物を選択',
  1176. 'sales.selectHarvest': '収穫を選択',
  1177. 'sales.noHarvest': '収穫記録がありません',
  1178. 'sales.date': '販売日',
  1179. 'sales.datePlaceholder': 'YYYY-MM-DD',
  1180. 'sales.quantity': '数量',
  1181. 'sales.quantityPlaceholder': '例: 50',
  1182. 'sales.unit': '単位',
  1183. 'sales.unitPlaceholder': 'kg',
  1184. 'sales.price': '価格',
  1185. 'sales.pricePlaceholder': '例: 35',
  1186. 'sales.priceLabel': '価格:',
  1187. 'sales.buyer': '買い手',
  1188. 'sales.buyerPlaceholder': '例: 地元市場',
  1189. 'sales.notes': 'メモ',
  1190. 'sales.notesPlaceholder': '支払い、輸送、品質...',
  1191. 'sales.fieldRequired': '圃場は必須です。',
  1192. 'sales.cropRequired': '作物は必須です。',
  1193. 'sales.quantityInvalid': '数量は数値で入力してください。',
  1194. 'sales.delete': '削除',
  1195. 'sales.deleteTitle': '販売記録を削除しますか?',
  1196. 'sales.deleteMessage': 'この操作は取り消せません。',
  1197. 'sales.cancel': 'キャンセル',
  1198. 'sales.pickFromGallery': 'ギャラリーから選ぶ',
  1199. 'sales.takeMedia': '写真 / 動画を撮る',
  1200. 'sales.save': '販売を保存',
  1201. 'sales.untitled': '販売',
  1202. 'sales.noField': '圃場なし',
  1203. 'sales.noCrop': '作物なし',
  1204. 'sales.edit': '販売を編集',
  1205. 'sales.update': '販売を更新',
  1206. 'costs.title': '費用記録',
  1207. 'costs.loading': '費用を読み込み中...',
  1208. 'costs.empty': '費用記録がまだありません。',
  1209. 'costs.saved': '保存しました。',
  1210. 'costs.saving': '保存中...',
  1211. 'costs.new': '新しい費用',
  1212. 'costs.field': '圃場',
  1213. 'costs.crop': '作物 (任意)',
  1214. 'costs.selectField': '圃場を選択',
  1215. 'costs.selectCrop': '作物を選択',
  1216. 'costs.category': 'カテゴリ',
  1217. 'costs.category.seed': '種子',
  1218. 'costs.category.fertilizer': '肥料',
  1219. 'costs.category.labor': '人件費',
  1220. 'costs.category.fuel': '燃料',
  1221. 'costs.category.equipment': '設備',
  1222. 'costs.category.transport': '輸送',
  1223. 'costs.category.misc': 'その他',
  1224. 'costs.categoryPlaceholder': '例: 種子',
  1225. 'costs.amount': '金額',
  1226. 'costs.amountPlaceholder': '例: 1200',
  1227. 'costs.vendor': '仕入先',
  1228. 'costs.vendorPlaceholder': '例: 地元の資材店',
  1229. 'costs.date': '日付',
  1230. 'costs.datePlaceholder': 'YYYY-MM-DD',
  1231. 'costs.notes': 'メモ',
  1232. 'costs.notesPlaceholder': '領収書、用途、目的...',
  1233. 'costs.photo': '領収書写真',
  1234. 'costs.addMedia': 'メディアを追加',
  1235. 'costs.pickFromGallery': 'ギャラリーから選ぶ',
  1236. 'costs.takeMedia': '写真 / 動画を撮る',
  1237. 'costs.pickPhoto': '写真を選ぶ',
  1238. 'costs.takePhoto': '写真を撮る',
  1239. 'costs.noPhoto': '写真が選択されていません。',
  1240. 'costs.fieldRequired': '圃場は必須です。',
  1241. 'costs.amountInvalid': '金額は数値で入力してください。',
  1242. 'costs.delete': '削除',
  1243. 'costs.deleteTitle': '費用記録を削除しますか?',
  1244. 'costs.deleteMessage': 'この操作は取り消せません。',
  1245. 'costs.cancel': 'キャンセル',
  1246. 'costs.save': '費用を保存',
  1247. 'costs.edit': '費用を編集',
  1248. 'costs.update': '費用を更新',
  1249. 'costs.untitled': '費用',
  1250. 'costs.noField': '圃場なし',
  1251. 'costs.noCrop': '作物なし',
  1252. 'units.kg': 'kg',
  1253. 'units.g': 'g',
  1254. 'units.ton': 't',
  1255. 'units.pcs': '個',
  1256. 'demo.field.north': '北圃場',
  1257. 'demo.field.northNote': '壌土 · 点滴灌漑',
  1258. 'demo.field.river': '川沿い区画',
  1259. 'demo.field.riverNote': '水路沿いの低地',
  1260. 'demo.field.greenhouse': '温室',
  1261. 'demo.field.greenhouseNote': '遮光ベッド、毎日灌漑',
  1262. 'demo.field.orchard': '果樹園区画',
  1263. 'demo.field.orchardNote': '畝立て、東側に防風林',
  1264. 'demo.field.terrace': '段々畑区画',
  1265. 'demo.field.terraceNote': '段々斜面に点滴ライン',
  1266. 'demo.crop.tomato': 'トマト',
  1267. 'demo.crop.tomatoVariety': 'チェリー',
  1268. 'demo.crop.rice': '米',
  1269. 'demo.crop.riceVariety': 'ジャスミン',
  1270. 'demo.crop.lettuce': 'レタス',
  1271. 'demo.crop.lettuceVariety': 'バターヘッド',
  1272. 'demo.crop.chili': '唐辛子',
  1273. 'demo.crop.chiliVariety': 'バードアイ',
  1274. 'demo.crop.cabbage': 'キャベツ',
  1275. 'demo.crop.cabbageVariety': '青キャベツ',
  1276. 'demo.observation.scoutingNote': '畝の端で初期の斑点を確認。',
  1277. 'demo.observation.diseaseNote': '雨の後に病斑が見られました。',
  1278. 'demo.observation.irrigationNote': '灌漑時間を夕方に調整。',
  1279. 'demo.observation.pestNote': '新芽にアブラムシを確認。',
  1280. 'demo.observation.nutrientNote': '下葉が淡く、葉面散布を実施。',
  1281. 'demo.task.note': '予定通り完了。',
  1282. 'demo.task.note2': '標準チェックリストを実施。',
  1283. 'demo.task.note3': '機材確認と記録を完了。',
  1284. 'demo.harvest.note1': '朝の収穫、品質良好。',
  1285. 'demo.harvest.note2': '小雨後に収穫。',
  1286. 'demo.harvest.note3': '市場向けにサイズ別選別。',
  1287. 'demo.sale.buyer1': '地元市場',
  1288. 'demo.sale.buyer2': '卸売業者',
  1289. 'demo.sale.buyer3': 'レストラン取引先',
  1290. 'demo.sale.note1': '当日配送。',
  1291. 'demo.sale.note2': '全額支払い済み。',
  1292. 'demo.sale.note3': '週次供給を依頼。',
  1293. 'demo.cost.vendor1': '農業資材店',
  1294. 'demo.cost.vendor2': '肥料店',
  1295. 'demo.cost.vendor3': '作業班',
  1296. 'demo.cost.note1': 'トマト種子とトレー。',
  1297. 'demo.cost.note2': '水田用の元肥。',
  1298. 'demo.cost.note3': '収穫補助(半日)。',
  1299. 'observations.type.scouting': '観察',
  1300. 'observations.type.pest': '害虫',
  1301. 'observations.type.disease': '病害',
  1302. 'observations.type.irrigation': '灌漑',
  1303. 'observations.type.weeds': '雑草',
  1304. 'observations.type.nutrients': '栄養',
  1305. 'crops.title': '作物',
  1306. 'crops.loading': '作物を読み込み中...',
  1307. 'crops.empty': '作物がまだありません。',
  1308. 'crops.saved': '保存しました。',
  1309. 'crops.saving': '保存中...',
  1310. 'crops.field': '圃場',
  1311. 'crops.selectField': '圃場を選択',
  1312. 'crops.name': '作物名',
  1313. 'crops.variety': '品種',
  1314. 'crops.planting': '定植日',
  1315. 'crops.harvest': '収穫予定',
  1316. 'crops.selectDate': '日付を選択',
  1317. 'crops.namePlaceholder': '例: トマト',
  1318. 'crops.varietyPlaceholder': '例: チェリー',
  1319. 'crops.plantingPlaceholder': 'YYYY-MM-DD',
  1320. 'crops.harvestPlaceholder': 'YYYY-MM-DD',
  1321. 'crops.fieldRequired': '圃場は必須です。',
  1322. 'crops.nameRequired': '作物名は必須です。',
  1323. 'crops.delete': '削除',
  1324. 'crops.deleteTitle': '作物を削除しますか?',
  1325. 'crops.deleteMessage': 'この操作は取り消せません。',
  1326. 'crops.noField': '圃場なし',
  1327. 'crops.untitled': '作物',
  1328. 'crops.plantingLabel': '定植:',
  1329. 'crops.harvestLabel': '収穫:',
  1330. 'crops.save': '作物を保存',
  1331. 'crops.new': '新しい作物',
  1332. 'crops.photo': '作物写真',
  1333. 'crops.addMedia': 'メディアを追加',
  1334. 'crops.pickFromGallery': 'ギャラリーから選ぶ',
  1335. 'crops.takeMedia': '写真 / 動画を撮る',
  1336. 'crops.pickPhoto': '写真を選ぶ',
  1337. 'crops.takePhoto': '写真を撮る',
  1338. 'crops.noPhoto': '写真が選択されていません。',
  1339. 'crops.today': '今日',
  1340. 'crops.done': '完了',
  1341. 'crops.edit': '作物を編集',
  1342. 'crops.update': '作物を更新',
  1343. 'crops.cancel': 'キャンセル',
  1344. },
  1345. };
  1346. export function createTranslator(language: Language) {
  1347. return (key: string, params?: Params) => {
  1348. const template = strings[language][key] ?? strings.en[key] ?? key;
  1349. if (!params) return template;
  1350. return Object.keys(params).reduce((result, paramKey) => {
  1351. return result.replace(
  1352. new RegExp(`{{${paramKey}}}`, 'g'),
  1353. String(params[paramKey])
  1354. );
  1355. }, template);
  1356. };
  1357. }
  1358. function getDeviceLanguage(): Language {
  1359. try {
  1360. const locale = Intl.DateTimeFormat().resolvedOptions().locale;
  1361. if (locale.toLowerCase().startsWith('th')) return 'th';
  1362. if (locale.toLowerCase().startsWith('ja')) return 'ja';
  1363. } catch {
  1364. // fall through
  1365. }
  1366. return 'en';
  1367. }
  1368. type LocalizationContextValue = {
  1369. language: Language;
  1370. setLanguage: (language: Language) => void;
  1371. t: (key: string, params?: Params) => string;
  1372. };
  1373. const LocalizationContext = createContext<LocalizationContextValue | null>(null);
  1374. export function LocalizationProvider({ children }: { children: ReactNode }) {
  1375. const [language, setLanguage] = useState<Language>(getDeviceLanguage());
  1376. const t = useCallback(
  1377. (key: string, params?: Params) => {
  1378. const template = strings[language][key] ?? strings.en[key] ?? key;
  1379. if (!params) return template;
  1380. return Object.keys(params).reduce((result, paramKey) => {
  1381. return result.replace(
  1382. new RegExp(`{{${paramKey}}}`, 'g'),
  1383. String(params[paramKey])
  1384. );
  1385. }, template);
  1386. },
  1387. [language]
  1388. );
  1389. const value = useMemo(
  1390. () => ({ language, setLanguage, t }),
  1391. [language, setLanguage, t]
  1392. );
  1393. return <LocalizationContext.Provider value={value}>{children}</LocalizationContext.Provider>;
  1394. }
  1395. export function useTranslation() {
  1396. const ctx = useContext(LocalizationContext);
  1397. if (!ctx) {
  1398. throw new Error('useTranslation must be used within LocalizationProvider');
  1399. }
  1400. return ctx;
  1401. }