Utils.ts 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. import {
  2. Prefab,
  3. resources,
  4. Node,
  5. find,
  6. instantiate,
  7. Vec3,
  8. log,
  9. Component,
  10. Button,
  11. warn,
  12. Asset,
  13. error,
  14. v2,
  15. UITransform,
  16. tween,
  17. v3,
  18. Vec2,
  19. director,
  20. ImageAsset,
  21. assetManager,
  22. } from "cc";
  23. import BigNumber from "./BigNumber";
  24. import { EDITOR } from "cc/env";
  25. import { LanguageManager } from "./LanguageManager";
  26. import PoolMgr from "./PoolMgr";
  27. import BaseUI from "../base/BaseUI";
  28. import { Tips } from "../mgr/Tips";
  29. import DisplayNumber from "./DisplayNumber";
  30. export enum EFLY_TYPE {
  31. 金币,
  32. 体力,
  33. 钻石,
  34. }
  35. export default class Utils {
  36. public static copyText(text: string) {
  37. navigator.clipboard.writeText(text).then(
  38. (res) => {
  39. console.log(" writeText success: ", res);
  40. // Tips.show(Utils.setI18nLabel("Share.LinkCopied"));
  41. },
  42. (err) => {
  43. console.log(" writeText error: ", err);
  44. this.copyTextFallback(text);
  45. }
  46. );
  47. }
  48. private static copyTextFallback(text) {
  49. const textArea = document.createElement("textarea");
  50. textArea.value = text;
  51. document.body.appendChild(textArea);
  52. textArea.select();
  53. try {
  54. document.execCommand("copy");
  55. Tips.show(Utils.setI18nLabel("Share.LinkCopied")); //"Link copied!");
  56. } catch (err) {
  57. Tips.show(Utils.setI18nLabel("Share.Title1"));
  58. }
  59. document.body.removeChild(textArea);
  60. }
  61. static sleep(ms: number) {
  62. return new Promise((resolve) => setTimeout(resolve, ms));
  63. }
  64. static padNumber(num, length): string {
  65. let str = num.toString();
  66. while (str.length < length) {
  67. str = "0" + str;
  68. }
  69. return str;
  70. }
  71. static log(o: any) {
  72. if ("1" == this.getQueryString("log")) {
  73. console.log(o);
  74. }
  75. }
  76. // 创建UI
  77. static createUI(
  78. filepath: string,
  79. parent: Node = null,
  80. callback: Function = null
  81. ): Promise<Node> {
  82. return new Promise((resolve, reject) => {
  83. resources.load(filepath, Prefab, (err, ret) => {
  84. log("加载UI:" + filepath);
  85. if (err) {
  86. console.error(err);
  87. reject();
  88. return;
  89. }
  90. if (parent == null) {
  91. parent = find("Canvas/popupNode");
  92. }
  93. let index = filepath.lastIndexOf("/");
  94. let name = filepath.substr(index + 1, filepath.length - index);
  95. if (parent.getComponentInChildren(name)) {
  96. console.log("重复UI跳过");
  97. return;
  98. }
  99. var tmp: Node = instantiate(ret);
  100. tmp.parent = parent;
  101. if (callback) callback(tmp);
  102. resolve(tmp);
  103. });
  104. });
  105. }
  106. // 创建预制体
  107. static createPrefab(
  108. filepath: string,
  109. parent: Node = null,
  110. callback: Function = null,
  111. pos: Vec3 = null
  112. ) {
  113. return new Promise((resolve, reject) => {
  114. resources.load(filepath, Prefab, (err, ret) => {
  115. if (err) {
  116. console.error(err);
  117. reject();
  118. return;
  119. }
  120. if (parent == null) {
  121. parent = find("Canvas");
  122. }
  123. var tmp: Node = instantiate(ret);
  124. // tmp.opacity = 0;
  125. // tmp.runAction(
  126. // sequence(
  127. // delayTime(0.01),
  128. // callFunc(() => {
  129. // tmp.opacity = 255;
  130. // })
  131. // )
  132. // );
  133. tmp.parent = parent;
  134. if (pos) {
  135. tmp.position = pos;
  136. }
  137. if (callback) callback(tmp);
  138. resolve(tmp);
  139. });
  140. });
  141. }
  142. // 获取随机数
  143. public static getRandom(lower, upper): number {
  144. return Math.random() * (upper - lower) + lower;
  145. }
  146. // 获取随机整数
  147. public static getRandomInt(lower, upper): number {
  148. return Math.floor(Math.random() * (upper - lower)) + lower;
  149. }
  150. // 获取随机整数
  151. public static seedRandomInt(lower, upper): number {
  152. return Utils.getRandomInt(lower, upper);
  153. }
  154. // 格式化数字
  155. public static formatNumber(num: number, afterdot: number = 2): string {
  156. num = Number(num);
  157. num = Number(num.toFixed(afterdot));
  158. if (num < 1000) {
  159. return num.toString();
  160. }
  161. return DisplayNumber.displayNumber(num,afterdot);
  162. // return BigNumber.getLargeString(num);
  163. }
  164. public static getPowNum(p) {
  165. return Math.pow(10, p);
  166. }
  167. // 设置服务器时间
  168. public static setServerTime(time: number) {
  169. Utils.timeOffset = time - new Date().getTime();
  170. }
  171. // 获取服务器时间
  172. public static timeOffset: number = 0;
  173. public static getServerTime() {
  174. return new Date().getTime() + Utils.timeOffset;
  175. }
  176. // 添加点击事件
  177. public static addClickEvent(
  178. node,
  179. target,
  180. component,
  181. handler,
  182. customEventData
  183. ) {
  184. var eventHandler = new Component.EventHandler();
  185. eventHandler.target = target;
  186. eventHandler.component = component;
  187. eventHandler.handler = handler;
  188. if (customEventData) eventHandler.customEventData = customEventData;
  189. var clickEvents = node.getComponent(Button).clickEvents;
  190. if (clickEvents.length > 0) {
  191. // if (!EDITOR) warn("按钮已经存在绑定,跳过自动绑定", node.name);
  192. return;
  193. }
  194. console.log(node.name, target.name, component);
  195. clickEvents.push(eventHandler);
  196. }
  197. public static secondsToDHMS(seconds) {
  198. if (seconds <= 0) {
  199. return `00d 00h:00m:00s`;
  200. }
  201. const days = Math.floor(seconds / (24 * 3600));
  202. let d = days < 9 ? "0" + days : days;
  203. const hours = Math.floor((seconds % (24 * 3600)) / 3600);
  204. let h = hours < 9 ? "0" + hours : hours;
  205. const minutes = Math.floor((seconds % 3600) / 60);
  206. let min = minutes < 9 ? "0" + minutes : minutes;
  207. const second = Math.floor(seconds % 60);
  208. let s = second < 9 ? "0" + second : second;
  209. let str = days > 0 ? `${d}d ${h}h:${min}m:${s}s` : `${h}h:${min}m:${s}s`;
  210. return str;
  211. }
  212. public static formatTimestamp(timestamp) {}
  213. // 秒转换为时分秒
  214. public static getToTimeByS(second: number) {
  215. const totalSeconds = Math.floor(second);
  216. const hours = Math.floor(totalSeconds / 3600) % 24;
  217. const minutes = Math.floor((totalSeconds % 3600) / 60);
  218. const seconds = totalSeconds % 60;
  219. return [hours, minutes, seconds]
  220. .map((unit) => (unit < 10 ? "0" + unit : unit.toString())) // 确保每个部分都是两位数
  221. .join(":"); // 拼接为字符串
  222. }
  223. private static padStartCustom(str, targetLength, padString) {
  224. str = String(str);
  225. padString = String(padString);
  226. if (str.length >= targetLength) {
  227. return str;
  228. }
  229. targetLength -= str.length;
  230. if (targetLength > padString.length) {
  231. padString = padString.repeat(Math.ceil(targetLength / padString.length));
  232. }
  233. return padString.slice(0, targetLength) + str;
  234. }
  235. public static formateDateRemaining(targetTimestamp: number) {
  236. const now = Utils.getServerTime();
  237. const remainingTime = targetTimestamp - now;
  238. const days = Math.floor(remainingTime / (1000 * 60 * 60 * 24));
  239. const hours = Math.floor(
  240. (remainingTime % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
  241. );
  242. const minutes = Math.floor(
  243. (remainingTime % (1000 * 60 * 60)) / (1000 * 60)
  244. );
  245. const seconds = Math.floor((remainingTime % (1000 * 60)) / 1000);
  246. const dStr = days < 10 ? "0" + days : days;
  247. const hStr = hours < 10 ? "0" + hours : hours;
  248. const mStr = minutes < 10 ? "0" + minutes : minutes;
  249. const sStr = seconds < 10 ? "0" + seconds : seconds;
  250. return `${dStr}d ${hStr}h:${mStr}m:${sStr}s`;
  251. }
  252. public static formatTimeRemaining(targetTimestamp) {
  253. // 获取当前时间戳
  254. const now = Date.now();
  255. // 计算剩余时间的毫秒数
  256. let remainingTime = targetTimestamp - now;
  257. // 如果剩余时间小于等于 0,表示目标时间已经过去
  258. if (remainingTime <= 0) {
  259. return "00:00:00";
  260. }
  261. // 计算小时、分钟、秒
  262. const hours = Math.floor(remainingTime / (1000 * 60 * 60));
  263. remainingTime -= hours * 1000 * 60 * 60;
  264. const minutes = Math.floor(remainingTime / (1000 * 60));
  265. remainingTime -= minutes * 1000 * 60;
  266. const seconds = Math.floor(remainingTime / 1000);
  267. // 格式化为两位数的字符串
  268. const formattedHours = Utils.padStartCustom(hours, 2, "0");
  269. const formattedMinutes = Utils.padStartCustom(minutes, 2, "0");
  270. const formattedSeconds = Utils.padStartCustom(seconds, 2, "0");
  271. return `${formattedHours}:${formattedMinutes}:${formattedSeconds}`;
  272. }
  273. // 秒转换为时分秒
  274. public static getTimeStrByS(second: number) {
  275. second = Math.floor(second);
  276. if (second < 0) second = 0;
  277. var d = Math.floor(second / 3600 / 24);
  278. second -= d * 3600 * 24;
  279. var h = Math.floor(second / 3600);
  280. second -= h * 3600;
  281. var m = Math.floor(second / 60);
  282. second -= m * 60;
  283. var front = "00";
  284. if (h > 9) {
  285. front = "" + h;
  286. } else {
  287. front = "0" + h;
  288. }
  289. var mid = "00";
  290. if (m > 9) {
  291. mid = "" + m;
  292. } else {
  293. mid = "0" + m;
  294. }
  295. var back = "00";
  296. if (second > 9) {
  297. back = "" + second;
  298. } else {
  299. back = "0" + second;
  300. }
  301. if (d > 0) {
  302. return d + ":" + h + ":" + m;
  303. } else {
  304. var longTime = h > 0;
  305. if (longTime) {
  306. return front + ":" + mid;
  307. } else {
  308. return mid + ":" + back; //+ '秒';
  309. }
  310. }
  311. }
  312. public static formattedDate(timestamp) {
  313. const date = new Date(Number(timestamp));
  314. // 获取年月日
  315. const year = date.getFullYear();
  316. let month = date.getMonth() + 1;
  317. let monthS = month < 9 ? "0" + month : month;
  318. let day = date.getDate();
  319. let dayS = day < 9 ? "0" + day : day;
  320. const hours = date.getHours();
  321. let hoursS = hours < 9 ? "0" + hours : hours;
  322. const minutes = date.getMinutes();
  323. let minutesS = minutes < 9 ? "0" + minutes : minutes;
  324. const seconds = date.getSeconds();
  325. let secondsS = seconds < 9 ? "0" + seconds : seconds;
  326. const formattedDate = `${year}-${monthS}-${dayS} ${hoursS}:${minutesS}:${secondsS}`;
  327. return formattedDate;
  328. }
  329. public static formattedOnlyDate(timestamp) {
  330. const date = new Date(Number(timestamp));
  331. // 获取年月日
  332. const year = date.getFullYear();
  333. let month = date.getMonth() + 1;
  334. let monthS = month < 9 ? "0" + month : month;
  335. let day = date.getDate();
  336. let dayS = day < 9 ? "0" + day : day;
  337. const formattedDate = `${year}-${monthS}-${dayS}`;
  338. return formattedDate;
  339. }
  340. // 格式化金币
  341. public static formatCoin(num: number) {
  342. num = Math.floor(num);
  343. return BigNumber.getLargeString(num);
  344. }
  345. // 加载资源
  346. public static loadRes(path: string, type: typeof Asset): Promise<Asset> {
  347. return new Promise((resolve, reject) => {
  348. resources.load(path, type, (err, ret) => {
  349. if (err) {
  350. error(path, err);
  351. reject(null);
  352. } else {
  353. resolve(ret);
  354. }
  355. });
  356. });
  357. }
  358. public static loadRemote(path: string, type: typeof ImageAsset) {
  359. return new Promise((resolve, reject) => {
  360. assetManager.loadRemote(path, type, (err, ret) => {
  361. if (err) {
  362. error(path, err);
  363. reject(null);
  364. } else {
  365. resolve(ret);
  366. }
  367. });
  368. });
  369. }
  370. // 权重
  371. public static weight(v: number[]): number {
  372. var mTotalWeight = 0;
  373. for (var i = 0; i < v.length; ++i) {
  374. mTotalWeight += v[i];
  375. }
  376. if (mTotalWeight <= 0) return -1;
  377. var randnum = Math.round(Math.random() * Number.MAX_VALUE) % mTotalWeight;
  378. for (var i = 0; i < v.length; ++i) {
  379. if (randnum < v[i]) {
  380. return i;
  381. } else {
  382. randnum -= v[i];
  383. }
  384. }
  385. return -1;
  386. }
  387. //定点数
  388. public static fixFloat(val: number, count: number = 2) {
  389. var a = count * 100;
  390. return Math.floor(val * a) / a;
  391. }
  392. // 在子节点中查找
  393. private static _findInChildren(node: Node, name: string): Node {
  394. var x = node.getChildByName(name);
  395. if (x) return x;
  396. if (node.children.length == 0) return null;
  397. for (var i = 0; i < node.children.length; ++i) {
  398. var tmp = this._findInChildren(node.children[i], name);
  399. if (tmp) return tmp;
  400. }
  401. return null;
  402. }
  403. // 飞动动画
  404. public static flyAnim(
  405. type: number,
  406. startNode: Node,
  407. targetNodeName: string,
  408. count: number,
  409. radius: number,
  410. callback: Function
  411. ) {
  412. let srcNode = this._findInChildren(director.getScene(), targetNodeName);
  413. if (!srcNode) {
  414. notPlay = false;
  415. callback();
  416. return;
  417. }
  418. let getPoint = (r, ox, oy, count) => {
  419. var point = []; //结果
  420. var radians = (Math.PI / 180) * Math.round(360 / count), //弧度
  421. i = 0;
  422. for (; i < count; i++) {
  423. var x = ox + r * Math.sin(radians * i),
  424. y = oy + r * Math.cos(radians * i);
  425. point.unshift(v2(x, y)); //为保持数据顺时针
  426. }
  427. return point;
  428. };
  429. let createNode = (type) => {
  430. if (type == 0) return PoolMgr.Instance().get("Coin");
  431. if (type == 1) return PoolMgr.Instance().get("Gem");
  432. if (type == 2) return PoolMgr.Instance().get("Zp");
  433. if (type == 3) return PoolMgr.Instance().get("ZpGold");
  434. };
  435. let start = startNode.parent
  436. .getComponent(UITransform)
  437. .convertToWorldSpaceAR(startNode.position);
  438. start = find("Canvas/flyNode")
  439. .getComponent(UITransform)
  440. .convertToNodeSpaceAR(start);
  441. var array = getPoint(radius, start.x, start.y, count);
  442. var nodeArray = new Array();
  443. for (var i = 0; i < array.length; i++) {
  444. var gold = createNode(type);
  445. gold.parent = find("Canvas/flyNode");
  446. var randPos = v2(
  447. array[i].x + Utils.getRandomInt(0, 50),
  448. array[i].y + Utils.getRandomInt(0, 50)
  449. );
  450. gold.setPosition(start);
  451. nodeArray.push({ gold, randPos });
  452. }
  453. var notPlay = false;
  454. let dstPos = srcNode.parent
  455. .getComponent(UITransform)
  456. .convertToWorldSpaceAR(srcNode.position);
  457. dstPos = find("Canvas/flyNode")
  458. .getComponent(UITransform)
  459. .convertToNodeSpaceAR(dstPos);
  460. var targetGoldNode = srcNode;
  461. for (var i = 0; i < nodeArray.length; i++) {
  462. var pos = nodeArray[i].randPos;
  463. var node = nodeArray[i].gold;
  464. nodeArray[i].gold.id = i;
  465. tween(node)
  466. .to(0.2, { position: pos })
  467. .delay(i * 0.03)
  468. .to(0.5, { position: v2(dstPos.x, dstPos.y) })
  469. .call(() => {
  470. if (!notPlay) {
  471. targetGoldNode.scale = v3(1, 1, 1);
  472. notPlay = true;
  473. tween(targetGoldNode)
  474. .to(0.1, { scale: v3(2, 2, 2) })
  475. .to(0.1, { scale: v3(1, 1, 1) })
  476. .call(() => {
  477. notPlay = false;
  478. });
  479. }
  480. callback(node._id == nodeArray.length - 1);
  481. PoolMgr.Instance().put(node.name, node);
  482. if (node._id == nodeArray.length - 1) {
  483. find("Canvas/flyNode").removeAllChildren();
  484. }
  485. })
  486. .start();
  487. }
  488. }
  489. /**
  490. * 深度复制
  491. * @param value
  492. */
  493. public static deepClone(value: any) {
  494. // 处理基本数据类型和特殊情况
  495. if (value === null || typeof value !== "object") {
  496. return value; // 基本数据类型和 null
  497. }
  498. // 处理数组
  499. if (Array.isArray(value)) {
  500. return value.map((item) => Utils.deepClone(item)); // 递归拷贝每个元素
  501. }
  502. // 处理对象
  503. const copy = {};
  504. for (const key in value) {
  505. if (value.hasOwnProperty(key)) {
  506. copy[key] = Utils.deepClone(value[key]); // 递归拷贝每个属性
  507. }
  508. }
  509. return copy;
  510. }
  511. /**
  512. * 获取url参数
  513. * @param name
  514. * @returns
  515. */
  516. public static getQueryString(name: any) {
  517. var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
  518. var r = window.location.search.substr(1).match(reg);
  519. if (r != null) return unescape(r[2]);
  520. return null;
  521. }
  522. /**
  523. * 贝塞尔曲线计算
  524. * @param points
  525. * @param t
  526. */
  527. public static calculateBezier(points: Vec2[], t: number) {
  528. const n = points.length;
  529. if (n === 0) return v2(0, 0); // 如果没有控制点,返回 (0,0)
  530. if (n === 1) return points[0]; // 如果只有一个控制点,返回该点
  531. let tempPoints = points.slice(); // 创建控制点的副本
  532. // De Casteljau's algorithm
  533. for (let r = 1; r < n; r++) {
  534. for (let i = 0; i < n - r; i++) {
  535. tempPoints[i] = v2(
  536. (1 - t) * tempPoints[i].x + t * tempPoints[i + 1].x,
  537. (1 - t) * tempPoints[i].y + t * tempPoints[i + 1].y
  538. );
  539. }
  540. }
  541. return tempPoints[0]; // 返回计算得到的点
  542. }
  543. /**
  544. * 是否为某个链接
  545. * @param url
  546. * @param hostname
  547. * @returns
  548. */
  549. static isNameLink(url: string | URL, hostname: string) {
  550. try {
  551. const parsedUrl = new URL(url);
  552. return parsedUrl.hostname === hostname;
  553. } catch (e) {
  554. console.error("Invalid URL");
  555. return false;
  556. }
  557. }
  558. // 将用户 ID 转换为 26 进制字符串
  559. public static convertTo26(userId) {
  560. let sb = "";
  561. while (userId > 0) {
  562. userId--;
  563. let ch = String.fromCharCode((userId % 26) + "A".charCodeAt(0));
  564. sb = ch + sb;
  565. userId = Math.floor(userId / 26);
  566. }
  567. return sb;
  568. }
  569. // 生成邀请代码
  570. public static generateInviteCode(channelId, userId) {
  571. return channelId + this.convertTo26(userId);
  572. }
  573. // 取后缀
  574. public static getSuffix(idx) {
  575. idx = Math.floor(idx);
  576. if (idx <= 0) {
  577. return "";
  578. }
  579. idx = idx - 1;
  580. let result = "";
  581. while (idx >= 0) {
  582. result = String.fromCharCode((idx % 26) + 97) + result;
  583. idx = Math.floor(idx / 26) - 1;
  584. }
  585. result = "";
  586. return result;
  587. }
  588. // max: 10 ==> 1->1,2->2,..10->10,11->1
  589. public static getMappedValue(idx, max) {
  590. let result;
  591. result = idx % max == 0 ? max : idx % max;
  592. return result;
  593. }
  594. //
  595. public static getStarValue(idx, max) {
  596. let result = Math.floor((idx - 1) / max);
  597. return result;
  598. }
  599. // 格式化地址
  600. static formAddress(address: string) {
  601. if (
  602. address == null ||
  603. address == "" ||
  604. address == undefined ||
  605. address.length < 10
  606. ) {
  607. return " ";
  608. }
  609. return (
  610. address.substring(0, 8) +
  611. "..." +
  612. address.substring(address.length - 8, address.length)
  613. );
  614. }
  615. //
  616. public static updateLabelText(fullText, maxWidth, fontSize) {
  617. let str = "";
  618. // 计算文本的实际宽度
  619. let textWidth = this.getTextWidth(fullText, fontSize);
  620. if (textWidth > maxWidth) {
  621. // 超过最大宽度,显示截断后的文本并加上省略号
  622. let truncatedText = this.truncateText(fullText, maxWidth, fontSize);
  623. str = truncatedText + "...";
  624. } else {
  625. // 显示完整文本
  626. str = fullText;
  627. }
  628. return str;
  629. }
  630. // 获取文本的宽度
  631. private static getTextWidth(text, fontSize) {
  632. let canvas = document.createElement("canvas");
  633. let ctx = canvas.getContext("2d");
  634. ctx.font = fontSize + "px Arial"; // 设置字体大小
  635. return ctx.measureText(text).width;
  636. }
  637. // 截断文本并返回适合的文本
  638. private static truncateText(text, maxWidth, fontSize) {
  639. let i = 0;
  640. let truncatedText = text;
  641. // 循环截取字符直到文本超出最大宽度
  642. while (
  643. this.getTextWidth(truncatedText, fontSize) > maxWidth &&
  644. i < text.length
  645. ) {
  646. i++;
  647. truncatedText = text.slice(0, text.length - i);
  648. }
  649. return truncatedText;
  650. }
  651. // 多语言
  652. static setI18nLabel(str: string, value?: string, value2?: string) {
  653. let i18nStr = str;
  654. i18nStr = LanguageManager.getText(str);
  655. if (value) {
  656. i18nStr = i18nStr.replace("{value}", value);
  657. }
  658. if (value2) {
  659. i18nStr = i18nStr.replace("{value2}", value2);
  660. }
  661. return i18nStr;
  662. }
  663. }