PolyTools Trade Cost 0.1.1 / src/lib/i18n.js

381 lines · 27,317 bytes · SHA-256 fc9361d9404faec2372202ea0b3c7240f1ddbced00f6187c0bc834d24060815f

1/* PolyTools — UI strings (en, ru). t('key', {var}) ; missing ru keys fall back to en. */
2(function (root) {
3 'use strict';
4
5 const en = {
6 'brand': 'PolyTools',
7 'unit.d': 'd', 'unit.h': 'h',
8 'common.notAffiliated': 'Not affiliated with Polymarket. Estimates for information only. Not financial or tax advice.',
9
10 // ---- trade panel ----
11 'panel.title': 'Real trade cost',
12 'panel.collapse': 'Collapse', 'panel.expand': 'Expand',
13 'panel.synced': 'synced with ticket', 'panel.manual': 'manual',
14 'panel.buy': 'Buy', 'panel.sell': 'Sell', 'panel.limit': 'Limit',
15 'panel.market': 'Market','panel.amountUsd': 'Amount, $', 'panel.shares': 'Shares',
16 'panel.pickMarket': 'Pick the market',
17 'panel.loading': 'Loading market data…',
18 'panel.loadFail': 'Could not load market data ({err}). Retrying…',
19 'panel.notMarketPage': 'Open a market page to see the real cost of a trade.',
20 'panel.enterAmount': 'Type an amount in the ticket and the full cost appears here.',
21 'panel.enterShares': 'Type the number of shares to sell.',
22 'panel.enterLimit': 'Set a limit price and shares.',
23 'panel.quoteBuy': 'At the best ask {price}: break-even {be}; a win pays {roi}',
24 'panel.quoteApr': '{apr}/yr',
25 'panel.quoteFee': 'Fee per $100: {fee}',
26 'panel.quoteSell': 'Best bid {price}; after fee you keep {net} per share',
27 'panel.ifWins': 'If it wins',
28 'panel.perYear': '/yr',
29 'panel.avgPrice': 'Avg fill price',
30 'panel.bestPrice': 'best {price}',
31 'panel.slippage': 'Slippage',
32 'panel.fee': 'Taker fee',
33 'panel.feeNone': 'no fee on this market',
34 'panel.perShare': 'per share',
35 'panel.withFee': 'with fee {price}',
36 'panel.ofAmount': 'of {usd} typed · {n} shares',
37 'panel.feePromo': 'fee-free promo on this market',
38 'panel.feeOfProfit': '{pct} of the win',
39 'panel.totalCost': 'You pay in total',
40 'panel.payout': 'Payout if it wins',
41 'panel.breakeven': 'Break-even chance',
42 'panel.breakevenHint': 'market mid {mid}',
43 'panel.edgeNeeded': 'you need {pp} over the market',
44 'panel.until': 'Until end date',
45 'panel.endPassed': 'end date passed',
46 'panel.apr': 'Annualized (simple)',
47 'panel.aprShort': 'Under 7 days: the annualized figure is not meaningful',
48 'panel.holding': 'Holding rewards ({rate}/yr)',
49 'panel.holdingVal': '≈ {usd} by end date',
50 'panel.withHolding': 'with rewards: {roi} · {apr}/yr',
51 'panel.makerBuy': 'Limit at {price} instead: same shares for {cost}, you save {saving} (fee + spread). Fill is not guaranteed.',
52 'panel.makerSell': 'Limit sell at {price}: +{gain} more. Fill is not guaranteed.',
53 'panel.proceeds': 'You receive (net)',
54 'panel.gross': 'Gross',
55 'panel.holdCompare': 'Holding pays {payout} if it wins. Selling is better only if you put the chance below {p}.',
56 'panel.limitTaker': 'Fills now as taker: {n} shares (fee {fee}). Rests on the book as maker: {m} shares (no fee).',
57 'panel.limitPassive': 'Rests on the book as a maker order, no fee.',
58 'panel.limitCost': 'Cost if fully filled',
59 'panel.limitNet': 'Net if fully filled',
60 'panel.updated': 'book {s}s ago',
61 'panel.openJournal': 'Trader journal',
62 'panel.settings': 'Settings',
63 'warn.unfilled': 'Not enough liquidity: {usd} would stay unfilled.',
64 'warn.unfilledShares': 'Not enough bids: {n} shares would stay unsold.',
65 'warn.slippage': 'High slippage: {pct} worse than the best price.',
66 'warn.feeEatsProfit': 'The fee eats {pct} of your potential profit.',
67 'warn.expired': 'End date has passed. Awaiting resolution, timing unknown.',
68 'warn.belowBenchmark': 'Below your benchmark of {b}/yr.',
69 'warn.noAsks': 'No sellers in the book.',
70 'warn.noBids': 'No buyers in the book.',
71 'warn.noFill': 'Nothing would fill at this size.',
72 'warn.closed': 'This market is not accepting orders.',
73 'warn.belowMinSize': 'Below the minimum order size ({n} shares).',
74 'warn.badInput': 'Check the limit price and shares.',
75 'profile.button': 'Journal for this trader',
76
77 // ---- popup ----
78 'popup.openJournal': 'Open trader journal',
79 'popup.journalHint': 'PnL by category, calibration, early exits, CSV export',
80 'popup.settings': 'Settings',
81 'popup.lang': 'Language', 'popup.lang.auto': 'Auto',
82 'popup.panel': 'Show the cost panel on Polymarket',
83 'popup.benchmark': 'Your benchmark return, %/yr',
84 'popup.benchmarkHint': 'e.g. what your cash earns elsewhere; trades below it get a warning',
85 'popup.saved': 'Saved',
86 'popup.privacy': 'Runs locally in your browser. Reads only public Polymarket APIs. No keys, no wallet access, no servers of ours.',
87
88 // ---- journal ----
89 'j.title': 'Trader journal',
90 'j.subtitle': 'Honest stats for any Polymarket wallet: where you win, where you leak, and whether your entries beat the price.',
91 'j.input': 'Wallet address, profile link or @username',
92 'j.load': 'Analyze', 'j.cancel': 'Stop', 'j.saved': 'Recent', 'j.remove': 'Remove',
93 'j.limit': 'Positions to analyze',
94 'j.err.resolve': 'Could not find this wallet or username.',
95 'j.err.load': 'Loading failed: {err}',
96 'j.err.empty': 'No positions found for this wallet.',
97 'j.step.profile': 'Profile and stats', 'j.step.pnl': 'PnL history', 'j.step.closed': 'Closed positions',
98 'j.step.open': 'Open positions', 'j.step.tokens': 'Resolutions', 'j.step.categories': 'Categories', 'j.step.build': 'Crunching numbers',
99 'j.truncated': 'Showing the latest {n} positions per status. Raise the limit for a complete picture.',
100 'j.loadedAt': 'Data as of {t}',
101 'j.kpi.net': 'Net result',
102 'j.kpi.netHint': 'after fees, plus rebates & rewards (Polymarket economic PnL)',
103 'j.kpi.positionPnl': 'Position PnL',
104 'j.kpi.positionPnlHint': 'after fees, finished + open',
105 'j.kpi.feesHint': 'already deducted · before fees: {x} (≈ Total PnL on the Polymarket profile)',
106 'j.kpi.fees': 'Fees paid',
107 'j.kpi.feesEntryOnly': 'entry fees of analyzed positions, already deducted',
108 'j.kpi.income': 'Rebates & rewards',
109 'j.kpi.winRate': 'Win rate',
110 'j.kpi.winRateHint': 'Wins {w} · losses {l}',
111 'j.kpi.pf': 'Profit factor',
112 'j.kpi.pfHint': 'gross wins ÷ gross losses',
113 'j.kpi.avgWinLoss': 'Avg win / avg loss',
114 'j.kpi.open': 'Open positions',
115 'j.kpi.openHint': 'Positions: {n} · unrealized {u}',
116 'j.kpi.markets': 'Markets traded',
117 'j.chart.pnl': 'Cumulative PnL',
118 'j.chart.pnlHint': 'Daily points from Polymarket (/v2/user-pnl, economic PnL).',
119 'j.chart.pnlEmpty': 'No PnL history published for this wallet yet.',
120 'j.cat.title': 'By category',
121 'j.cat.hint': 'Finished positions, PnL after fees.',
122 'j.cat.col.category': 'Category', 'j.cat.col.n': 'Finished', 'j.cat.col.wr': 'Win rate', 'j.cat.col.pnl': 'PnL',
123 'j.cat.col.roi': 'ROI','j.cat.col.open': 'Open',
124 'j.cal.title': 'Calibration of your entries',
125 'j.cal.hint': 'Each dot is a price bucket: what you paid on average vs how often that outcome actually paid out. Dots above the diagonal mean you bought cheaper than reality, dots below mean you overpaid. Whiskers show the 95% interval.',
126 'j.cal.edge': 'Average edge per entry',
127 'j.cal.moneyEdge': 'Dollar-weighted edge',
128 'j.cal.paid': 'Paid (avg)', 'j.cal.won': 'Actual win rate', 'j.cal.n': 'Positions', 'j.cal.bucket': 'Entry price',
129 'j.cal.edgeCol': 'Edge', 'j.cal.few': 'few data',
130 'j.cal.axisX': 'Average entry price', 'j.cal.axisY': 'Share that won',
131 'j.beh.title': 'Behaviour',
132 'j.beh.held': 'Held to resolution',
133 'j.beh.exited': 'Exited before resolution',
134 'j.beh.saved': 'Early exits saved you',
135 'j.beh.missed': 'Early exits cost you',
136 'j.beh.deltaHint': 'vs holding the same shares to resolution',
137 'j.beh.holdWin': 'Median holding time, winners',
138 'j.beh.holdLoss': 'Median holding time, losers',
139 'j.beh.long': 'Longshots (<15¢)', 'j.beh.mid': 'Middle (15-85¢)', 'j.beh.fav': 'Favourites (>85¢)',
140 'j.month.title': 'Month by month',
141 'j.month.hint': 'Finished positions by the month of their last trade or redemption (UTC).',
142 'j.month.col.month': 'Month', 'j.month.col.n': 'Finished', 'j.month.col.wl': 'W / L', 'j.month.col.pnl': 'PnL',
143 'j.top.best': 'Best positions', 'j.top.worst': 'Worst positions',
144 'j.top.col.market': 'Market', 'j.top.col.entry': 'Entry', 'j.top.col.pnl': 'PnL', 'j.top.col.closed': 'Closed',
145 'j.export.title': 'Export',
146 'j.export.positions': 'Positions CSV',
147 'j.export.monthly': 'Monthly CSV',
148 'j.export.activity': 'Full activity ledger CSV',
149 'j.export.year': 'Period',
150 'j.export.allTime': 'All time',
151 'j.export.loading': 'Fetching activity… {n} rows',
152 'j.export.done': 'Saved {n} rows',
153 'j.export.hint': 'The ledger includes trades, redemptions, splits/merges, rewards, rebates, deposits and withdrawals in UTC. Polymarket computes PnL with average cost. This is data for your accountant and is not tax advice.',
154 'j.table.show': 'Show table', 'j.table.hide': 'Hide table',
155 'j.cat.esports': 'Esports', 'j.cat.sports': 'Sports', 'j.cat.crypto': 'Crypto', 'j.cat.weather': 'Weather',
156 'j.cat.mentions': 'Mentions', 'j.cat.tech': 'Tech', 'j.cat.culture': 'Culture', 'j.cat.economy': 'Economy',
157 'j.cat.finance': 'Finance', 'j.cat.geopolitics': 'Geopolitics', 'j.cat.politics': 'Politics', 'j.cat.other': 'Other',
158 'j.note.pnl': 'PnL follows Polymarket: average cost, net of trading fees. Rebates and rewards are added on top (wallet profile stats). Combo and LP results count only in the headline numbers.',
159 'panel.noBook': 'No order book for this market (it is closed or resolved).',
160 'j.kpi.statsAsOf': 'Polymarket profile stats as of {t}',
161 'j.kpi.basedOn': 'From the {n} analyzed positions',
162 'j.chart.col.date': 'Date',
163 'j.cal.empty': 'No resolved positions yet.',
164 'j.notice.categories': 'Categories for {n} events could not be loaded and are shown as Other.',
165 'panel.levelsN': 'levels: {n}',
166 'panel.enterManual': 'Enter a value above to see the full cost.',
167 'panel.openPanel': 'Open PolyTools',
168 'panel.minimize': 'Minimize',
169 'panel.summaryBuy': 'If it wins {profit} · break-even {be} · fee {fee}',
170 'panel.summarySell': 'You receive {net} · fee {fee}',
171 'j.stopped': 'Stopped. Press Analyze to load again.',
172 'j.notice.tokens': 'Resolution status could not be loaded for {n} positions; they are treated as open.',
173 'j.export.capped': 'Row limit reached: {n}.',
174 'panel.live': 'live book',
175 'panel.oneTap': 'One-tap amounts, payout after fees',
176 'panel.oneTapSub': 'button says {claim} · fee {fee}',
177 'popup.also': 'Also free from PolyTools:',
178 'popup.privacyLink': 'Privacy policy',
179 'popup.follow': 'News and new tools:',
180 };
181
182 const ru = {
183 'unit.d': 'дн.', 'unit.h': 'ч',
184 'common.notAffiliated': 'Не связано с Polymarket. Оценки только для информации. Не финансовая и не налоговая консультация.',
185
186 'panel.title': 'Реальная цена сделки',
187 'panel.collapse': 'Свернуть', 'panel.expand': 'Развернуть',
188 'panel.synced': 'синхронизировано с тикетом', 'panel.manual': 'вручную',
189 'panel.buy': 'Покупка', 'panel.sell': 'Продажа', 'panel.limit': 'Лимитка',
190 'panel.market': 'Рынок','panel.amountUsd': 'Сумма, $', 'panel.shares': 'Акций',
191 'panel.pickMarket': 'Выберите рынок',
192 'panel.loading': 'Загружаю данные рынка…',
193 'panel.loadFail': 'Не удалось загрузить данные ({err}). Пробую ещё…',
194 'panel.notMarketPage': 'Откройте страницу рынка, и я покажу реальную цену сделки.',
195 'panel.enterAmount': 'Введите сумму в тикете, и здесь появится полная стоимость.',
196 'panel.enterShares': 'Введите, сколько акций продаёте.',
197 'panel.enterLimit': 'Укажите лимитную цену и количество акций.',
198 'panel.quoteBuy': 'По лучшему аску {price}: безубыточность {be}; при выигрыше {roi}',
199 'panel.quoteApr': '{apr} годовых',
200 'panel.quoteFee': 'Комиссия на $100: {fee}',
201 'panel.quoteSell': 'Лучший бид {price}; после комиссии остаётся {net} за акцию',
202 'panel.ifWins': 'Если выиграет',
203 'panel.perYear': ' годовых',
204 'panel.avgPrice': 'Средняя цена исполнения',
205 'panel.bestPrice': 'лучшая {price}',
206 'panel.slippage': 'Проскальзывание',
207 'panel.fee': 'Комиссия тейкера',
208 'panel.feeNone': 'на этом рынке нет комиссии',
209 'panel.perShare': 'за акцию',
210 'panel.withFee': 'с комиссией {price}',
211 'panel.ofAmount': 'из {usd} в тикете · акций: {n}',
212 'panel.feePromo': 'на рынке акция без комиссии',
213 'panel.feeOfProfit': '{pct} от выигрыша',
214 'panel.totalCost': 'Итого спишется',
215 'panel.payout': 'Выплата при выигрыше',
216 'panel.breakeven': 'Безубыточная вероятность',
217 'panel.breakevenHint': 'рынок: {mid}',
218 'panel.edgeNeeded': 'нужно на {pp} выше рынка',
219 'panel.until': 'До даты окончания',
220 'panel.endPassed': 'дата прошла',
221 'panel.apr': 'Годовых (простые)',
222 'panel.aprShort': 'Меньше 7 дней: годовые не показательны',
223 'panel.holding': 'Holding Rewards ({rate} годовых)',
224 'panel.holdingVal': '≈ {usd} до даты окончания',
225 'panel.withHolding': 'с наградами: {roi} · {apr} годовых',
226 'panel.makerBuy': 'Лимиткой по {price}: те же акции за {cost}, экономия {saving} (комиссия + спред). Исполнение не гарантировано.',
227 'panel.makerSell': 'Лимиткой на продажу по {price}: +{gain}. Исполнение не гарантировано.',
228 'panel.proceeds': 'Получите (чистыми)',
229 'panel.gross': 'До комиссии',
230 'panel.holdCompare': 'Если держать, при выигрыше выплата составит {payout}. Продавать выгоднее, только если вы оцениваете шанс ниже {p}.',
231 'panel.limitTaker': 'Сразу как тейкер: {n} шт. (комиссия {fee}). В книгу как мейкер: {m} шт. (без комиссии).',
232 'panel.limitPassive': 'Встанет в книгу как мейкерская заявка, без комиссии.',
233 'panel.limitCost': 'Стоимость при полном исполнении',
234 'panel.limitNet': 'Чистыми при полном исполнении',
235 'panel.updated': 'стакан {s} с назад',
236 'panel.openJournal': 'Дневник трейдера',
237 'panel.settings': 'Настройки',
238 'warn.unfilled': 'Не хватает ликвидности: {usd} останутся неисполненными.',
239 'warn.unfilledShares': 'Не хватает бидов: не продастся {n} шт.',
240 'warn.slippage': 'Сильное проскальзывание: на {pct} хуже лучшей цены.',
241 'warn.feeEatsProfit': 'Комиссия съедает {pct} потенциальной прибыли.',
242 'warn.expired': 'Дата окончания прошла. Ждём резолюцию, сроки неизвестны.',
243 'warn.belowBenchmark': 'Ниже вашего ориентира {b} годовых.',
244 'warn.noAsks': 'В стакане нет продавцов.',
245 'warn.noBids': 'В стакане нет покупателей.',
246 'warn.noFill': 'На таком объёме ничего не исполнится.',
247 'warn.closed': 'Рынок не принимает заявки.',
248 'warn.belowMinSize': 'Меньше минимального размера заявки (минимум {n} шт.).',
249 'warn.badInput': 'Проверьте лимитную цену и количество.',
250 'profile.button': 'Дневник этого трейдера',
251
252 'popup.openJournal': 'Открыть дневник трейдера',
253 'popup.journalHint': 'PnL по категориям, калибровка, ранние выходы, экспорт CSV',
254 'popup.settings': 'Настройки',
255 'popup.lang': 'Язык', 'popup.lang.auto': 'Авто',
256 'popup.panel': 'Показывать панель стоимости на Polymarket',
257 'popup.benchmark': 'Ваш ориентир доходности, % годовых',
258 'popup.benchmarkHint': 'например, сколько ваши деньги приносят в другом месте. Сделки ниже получат предупреждение',
259 'popup.saved': 'Сохранено',
260 'popup.privacy': 'Работает локально в браузере. Читает только публичные API Polymarket. Без ключей, без доступа к кошельку, без наших серверов.',
261
262 'j.title': 'Дневник трейдера',
263 'j.subtitle': 'Честная статистика любого кошелька Polymarket: где вы зарабатываете, где сливаете и бьют ли ваши входы цену.',
264 'j.input': 'Адрес кошелька, ссылка на профиль или @username',
265 'j.load': 'Анализировать', 'j.cancel': 'Стоп', 'j.saved': 'Недавние', 'j.remove': 'Удалить',
266 'j.limit': 'Сколько позиций анализировать',
267 'j.err.resolve': 'Не нашёл такой кошелёк или имя.',
268 'j.err.load': 'Ошибка загрузки: {err}',
269 'j.err.empty': 'У этого кошелька нет позиций.',
270 'j.step.profile': 'Профиль и статистика', 'j.step.pnl': 'История PnL', 'j.step.closed': 'Закрытые позиции',
271 'j.step.open': 'Открытые позиции', 'j.step.tokens': 'Исходы рынков', 'j.step.categories': 'Категории', 'j.step.build': 'Считаю',
272 'j.truncated': 'Показаны последние {n} позиций каждого статуса. Увеличьте лимит для полной картины.',
273 'j.loadedAt': 'Данные на {t}',
274 'j.kpi.net': 'Итог',
275 'j.kpi.netHint': 'после комиссий, плюс ребейты и награды (economic PnL Polymarket)',
276 'j.kpi.positionPnl': 'PnL позиций',
277 'j.kpi.positionPnlHint': 'после комиссий, закрытые + открытые',
278 'j.kpi.feesHint': 'уже вычтены · до комиссий: {x} (≈ Total PnL в профиле Polymarket)',
279 'j.kpi.fees': 'Комиссии',
280 'j.kpi.feesEntryOnly': 'комиссии на вход по проанализированным позициям, уже вычтены',
281 'j.kpi.income': 'Ребейты и награды',
282 'j.kpi.winRate': 'Доля побед',
283 'j.kpi.winRateHint': 'Побед {w} · поражений {l}',
284 'j.kpi.pf': 'Профит-фактор',
285 'j.kpi.pfHint': 'сумма выигрышей ÷ сумма проигрышей',
286 'j.kpi.avgWinLoss': 'Средний выигрыш / проигрыш',
287 'j.kpi.open': 'Открытые позиции',
288 'j.kpi.openHint': 'Позиций: {n} · нереализовано {u}',
289 'j.kpi.markets': 'Рынков торговали',
290 'j.chart.pnl': 'Накопленный PnL',
291 'j.chart.pnlHint': 'Дневные точки из Polymarket (/v2/user-pnl, economic PnL).',
292 'j.chart.pnlEmpty': 'Polymarket ещё не опубликовал историю PnL для этого кошелька.',
293 'j.cat.title': 'По категориям',
294 'j.cat.hint': 'Завершённые позиции, PnL после комиссий.',
295 'j.cat.col.category': 'Категория', 'j.cat.col.n': 'Завершено', 'j.cat.col.wr': 'Доля побед', 'j.cat.col.pnl': 'PnL',
296 'j.cat.col.roi': 'ROI','j.cat.col.open': 'Открыто',
297 'j.cal.title': 'Калибровка ваших входов',
298 'j.cal.hint': 'Точки показывают ценовые корзины: сколько вы в среднем платили и как часто этот исход реально выигрывал. Точка выше диагонали значит, что вы покупали дешевле реальности, ниже диагонали значит переплачивали. Усы показывают 95% интервал.',
299 'j.cal.edge': 'Средний перевес на вход',
300 'j.cal.moneyEdge': 'Перевес, взвешенный по деньгам',
301 'j.cal.paid': 'Платили (ср.)', 'j.cal.won': 'Выиграло', 'j.cal.n': 'Позиций', 'j.cal.bucket': 'Цена входа',
302 'j.cal.edgeCol': 'Перевес', 'j.cal.few': 'мало данных',
303 'j.cal.axisX': 'Средняя цена входа', 'j.cal.axisY': 'Доля выигравших',
304 'j.beh.title': 'Поведение',
305 'j.beh.held': 'Держали до резолюции',
306 'j.beh.exited': 'Вышли до резолюции',
307 'j.beh.saved': 'Ранние выходы сберегли',
308 'j.beh.missed': 'Ранние выходы стоили',
309 'j.beh.deltaHint': 'по сравнению с удержанием тех же акций до резолюции',
310 'j.beh.holdWin': 'Медианное удержание: победы',
311 'j.beh.holdLoss': 'Медианное удержание: поражения',
312 'j.beh.long': 'Лонгшоты (<15¢)', 'j.beh.mid': 'Середина (15-85¢)', 'j.beh.fav': 'Фавориты (>85¢)',
313 'j.month.title': 'По месяцам',
314 'j.month.hint': 'Завершённые позиции по месяцу последней сделки или выплаты (UTC).',
315 'j.month.col.month': 'Месяц', 'j.month.col.n': 'Завершено', 'j.month.col.wl': 'П / П', 'j.month.col.pnl': 'PnL',
316 'j.top.best': 'Лучшие позиции', 'j.top.worst': 'Худшие позиции',
317 'j.top.col.market': 'Рынок', 'j.top.col.entry': 'Вход', 'j.top.col.pnl': 'PnL', 'j.top.col.closed': 'Закрыта',
318 'j.export.title': 'Экспорт',
319 'j.export.positions': 'CSV позиций',
320 'j.export.monthly': 'CSV по месяцам',
321 'j.export.activity': 'CSV всех операций',
322 'j.export.year': 'Период',
323 'j.export.allTime': 'За всё время',
324 'j.export.loading': 'Загружаю операции… строк: {n}',
325 'j.export.done': 'Сохранено строк: {n}',
326 'j.export.hint': 'В выгрузку входят сделки, выплаты, split/merge, награды, ребейты, депозиты и выводы, время в UTC. Polymarket считает PnL по средней цене. Это данные для бухгалтера, налоговой консультацией они не являются.',
327 'j.table.show': 'Показать таблицу', 'j.table.hide': 'Скрыть таблицу',
328 'j.cat.esports': 'Киберспорт', 'j.cat.sports': 'Спорт', 'j.cat.crypto': 'Крипта', 'j.cat.weather': 'Погода',
329 'j.cat.mentions': 'Упоминания', 'j.cat.tech': 'Технологии', 'j.cat.culture': 'Культура', 'j.cat.economy': 'Экономика',
330 'j.cat.finance': 'Финансы', 'j.cat.geopolitics': 'Геополитика', 'j.cat.politics': 'Политика', 'j.cat.other': 'Другое',
331 'j.note.pnl': 'PnL считается как у Polymarket: по средней цене, после торговых комиссий. Ребейты и награды добавляются сверху (статистика профиля). Комбо и LP учтены только в итоговых цифрах.',
332 'panel.noBook': 'У этого рынка нет стакана: он закрыт или разрешён.',
333 'j.kpi.statsAsOf': 'Статистика профиля Polymarket на {t}',
334 'j.kpi.basedOn': 'По проанализированным позициям: {n}',
335 'j.chart.col.date': 'Дата',
336 'j.cal.empty': 'Пока нет разрешённых позиций.',
337 'j.notice.categories': 'Не удалось загрузить категории для событий: {n}. Они показаны как «Другое».',
338 'panel.levelsN': 'уровней: {n}',
339 'panel.enterManual': 'Введите значение выше, и появится полная стоимость.',
340 'panel.openPanel': 'Открыть PolyTools',
341 'panel.minimize': 'Свернуть в значок',
342 'panel.summaryBuy': 'При выигрыше {profit} · безубыточность {be} · комиссия {fee}',
343 'panel.summarySell': 'Получите {net} · комиссия {fee}',
344 'j.stopped': 'Остановлено. Нажмите «Анализировать», чтобы загрузить снова.',
345 'j.notice.tokens': 'Не удалось загрузить исход для позиций: {n}. Они считаются открытыми.',
346 'j.export.capped': 'Достигнут лимит строк: {n}.',
347 'panel.live': 'стакан онлайн',
348 'panel.oneTap': 'Суммы 1-Tap: выплата после комиссии',
349 'panel.oneTapSub': 'на кнопке {claim} · комиссия {fee}',
350 'brand': 'PolyTools',
351 'popup.also': 'Ещё бесплатно от PolyTools:',
352 'popup.privacyLink': 'Политика конфиденциальности',
353 'popup.follow': 'Новости и новые инструменты:',
354 };
355
356 const dicts = { en, ru };
357 let lang = 'en';
358
359 function detect() {
360 const nav = ((typeof navigator !== 'undefined' && (navigator.language || '')) || '').toLowerCase();
361 const base = nav.split('-')[0];
362 return dicts[base] ? base : 'en';
363 }
364
365 function setLang(l) {
366 lang = l && l !== 'auto' && dicts[l] ? l : detect();
367 if (root.PWL && root.PWL.fmt) root.PWL.fmt.setLocale(lang);
368 return lang;
369 }
370
371 function t(key, vars) {
372 let s = (dicts[lang] && dicts[lang][key]) || en[key] || key;
373 if (vars) s = s.replace(/\{(\w+)\}/g, (m, k) => (vars[k] != null ? String(vars[k]) : m));
374 return s;
375 }
376
377 const i18n = { t, setLang, detect, get lang() { return lang; }, dicts };
378 root.PWL = root.PWL || {};
379 root.PWL.i18n = i18n;
380 if (typeof module !== 'undefined' && module.exports) module.exports = i18n;
381})(typeof globalThis !== 'undefined' ? globalThis : this);