JavaGUI:多功能计算器(五)--Swing实现双语数据包+菜单切换(完整源码+EXE下载)

JavaGUI:多功能计算器(五)–Swing实现双语数据包+菜单切换(完整源码+EXE下载)

本文资源下载:

程序源码及可独立运行的EXE文件自解压包(32bit/64bit):
多功能计算器v0.41【双语界面32bitEXE文件+JRE+JAR+源码】
多功能计算器v0.41【双语界面64bitEXE文件+JAR+源码】

资源说明:

本程序编译环境为jdk-18.0.2.1版本,独立运行环境也必须与之兼容;
自解压包中已包含jre32bit独立运行环境(精简38M,原版174M);
因网上没有找到合适可用的jre32bit精简版,便自己制作了一个,版本号为jre32bit-8.0.201.9;为了兼顾通用性,只删除了原版的几个大文件以及重新压缩了rt.jar;
运行默认目录为".\jre"或".\jre8x32";即放在exe文件的当前运行目录即可,无需安装;也可用RAR或ZIP手动解压,查看即可。
(jre64bit版本很容易在网上找到,运行默认目录为".\jre"或".\jre8x64";即放在exe文件的当前运行目录即可)

【背景提示】

“软件国际化”就是实现多种语言显示切换:
1.在前端网页上,可通过探测本地化语言环境实现自动切换;
2.在操作系统如Win10中,有各种显示语言包,可以下载/安装/卸载;
3.在应用程序App中,有专门的语言数据包,如中文/日文语言包等。

一、多国语言包简单实现:

在java的SwingGUI中,可以方便地实现双语悬停提示,但要实现语言包功能,难点就是要设计好语言包的格式。

本文实现方法:

提示: 这里的Lang[ ][ ]和LANG[ ][ ]与java本身的语言包java.lang毫无关系)

  1. 语言包使用Java的二维可变长数组,即源码中的语言数组LANG[ ][ ];方法中的形参为Lang[ ][ ];
  2. 将GUI界面需显示的字符串进行分组,如源码中的按键组“pkeys”和菜单组“menu”;
  3. 在字串分组里又按 “组信息+英文组+中文组+俄文组…”的顺序排列;
  4. 各分组之间的顺序可任意排列,保持编辑修改的灵活性;

实现的功能:

  1. 保留前文v0.40版本的鼠标悬停双语互提示功能,由全局变量iLang判别;
  2. 菜单切换中英文界面;切换后可同时看到两个窗口,但“焦点”在最后启动的窗口;关闭焦点窗口会同时关闭前导窗口,而关闭前导窗口不会关闭焦点窗口;
  3. 在中文窗口,程序后面的命令执行部分仍然使用英文命令,中文命令由命令索引方法cmdIndex()实现自动转换;详情参见后面的完整源码;

二、完整源码:(创新版)

提示: 本源码版本为v0.41;在v0.34与v0.40基础上仅重写了窗口的初始化部分;后面的按键和菜单命令执行部分与前文v0.34基本相同;

//TODO v0.41;20230101w0;JavaSwing实现多语言菜单切换@多功能计算器;同时保留双语悬停提示;
//文章标签: java gui awt swing eclipse
//版本说明:
//v0.41;20230101w0;JavaSwing实现多语言数据包@多功能计算器;双语菜单切换+悬停提示,创新版;
//v0.40;20221230;JavaSwing实现双语悬停提示@多功能计算器; AWT到Swing直接升级版;


package calculator;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


public class Calculate
{
    //v0.34;20221005;总体布局;完整版3位版本号;简易版仅需1位版本号;   	
	//v0.40;20221230(AWT2Swing直接升级版);
	//计算变量:
	private double 		num1,num2,mem;					//操作数1/2,中间记忆mem,均为double;
	private boolean 	isNum;							//数字拼接标志位,转存后失效;
	private String 		Oper;							//二元计算操作符,依赖"="计算;
	//显示变量:
	private JTextArea 	tRecord;						//操作记录;多行可编辑复制;用CR按键清空;
	private JTextField 	tResult;						//计算结果;单行可退格,由C按键复制后清空;
	//主框架:
	private JFrame 		frame;
	private int 		wFrame;
	private int 		hFrame;
	private int 		iLang=0;						//语言代码:默认0英文,,1中文;2俄文,3韩文,4日文;
	//v0.41;20230101;定义窗口语言数据包;
	private final String[][] LANG = {
		{"language","1","0"},
		{"English","Chinese","Russian"},				//iLang=0,1,2;
		{"英语","汉语","俄语"},
		{"about","1","100","70"},
		{"About","Auther: yy-2020."},
		{"关于DbY","作者: yy-2020."},
		{"frame","1","590","270","res/yy-2020.png"},	//主框架frame,大小及图标文件;
		{"Calculator V0.41"},
		{"计算器DbY v0.41"},
		{"textshow","1","5","20"},						//文本显示,默认5行25列;
		{"RecordArea\n","ResultField"},
		{"操作记录区\n","计算结果"},
		{"pkeys","7","8"},								//按键板,默认7行8列;
		{"temp"	,"f(x)"	,"n!"	,"("	,"d"	,"e"	,"f"	,"x^y"},
		{"tone"	,"log10","cbrt"	,")"	,"a"	,"b"	,"c"	,"%"},	
		{"tune"	,"tan"	,"sqrt"	,"MC"	,"7"	,"8"	,"9"	,"/"}, 
		{"oct"	,"cos"	,"x^3"	,"M"	,"4"	,"5"	,"6"	,"*"},
		{"sus"	,"sin"	,"x^2"	,"E"	,"1"	,"2"	,"3"	,"-"}, 
		{"chrd"	,"rand"	,"1/x"	,"PI"	,"0"	,"."	,"-/+"	,"+"},
		{"midi"	,"time"	,"dec"	,"hex"	,"CR"	,"C"	,"BS"	,"="},
		{"速度"	,"函数"	,"阶乘"	,"("	,"d"	,"e"	,"f"	,"乘方"},
		{"音色"	,"对数10","立方根",")"	,"a"	,"b"	,"c"	,"取余"},	
		{"变调"	,"正切"	,"平方根","清存储","7"	,"8"	,"9"	,"除"}, 
		{"八度"	,"余弦"	,"立方"	,"存储"	,"4"	,"5"	,"6"	,"乘"},
		{"延音"	,"正弦"	,"平方"	,"欧拉数","1"	,"2"	,"3"	,"减"}, 
		{"和弦"	,"随机数","倒数"	,"圆周率","0"	,"."	,"取负"	,"加"},
		{"编曲"	,"时间"	,"10进制","16进制","清记录","清结果","退格","="},
		{"menu","5","0"},								//菜单定义;
		{"File","Open","Save","saveTo","Exit"},
		{"Option","Typical","Personal","Multifunc","Default","Set"},
		{"Help","tTip","tShow","About","Example","Constant","Formula"},
		{"eXtends","Music","Calendar","Weather","Health"},
		{"Language","English","Chinese"},
		{"文件","打开","保存","另存","退出"},				
		{"选项","典型","个性","多功能","默认","多选"},			
		{"帮助","提示","显示","关于","示例","常数","公式"},			
		{"扩展","音乐","日历","天气","健康"},	
		{"语言","英文","中文"},		
	};
	
	//v0.41;20230103;语言数据包LANG[][]串组分类索引方法;类串cStr;返回类串索引号i;
	private int classIndex(String cStr,String[][] Lang) {		
		for(int i=0;i<Lang.length;i++) {
			if(Lang[i][0]==cStr) return i;				//返回类串索引号i;
		}return -1;										//未找到匹配项,返回异常;								
	}
	//v0.41;20230108;英语命令回归索引方法;为新增的双语串组LANG[][]专门改写的版本;
	private String cmdIndex(String str,String cStr,String[][] Lang) {
		int s = classIndex(cStr,Lang); 					//本类起始行号s@Lang[][];
		int nRow = Integer.parseInt(Lang[s+0][1]);		//本类行数nRow@Lang[][];
		for(int i=nRow*2;i>0;i--) {
			for(int j=0;j<Lang[s+i].length;j++) {
				if(Lang[s+i][j]==str)
					return Lang[s+i-(i<nRow?0:nRow)][j];//返回对应英语命令串;
			}
		}return "xxx";									//未找到匹配项,返回错误串;
	}
	//v0.34;20221005;将原init()中创建键盘按钮的程序段独立为方法,便于实现中英双语界面;
	//v0.40;20221230;AWT2Swing直接升级版;并增加中文悬停提示;
	//v0.41;20230102;为新增的双语串组LANG[][]专门改写的版本;
	private void CreateButtons(JPanel owner,String[][] Lang,int s) {
		int nRow=Integer.parseInt(Lang[s+0][1]);		//键组行数@[s+0][1];
		JButton [][]keys = new JButton[nRow][];			//创建按钮组;
		for (int i = 0; i < nRow; i++){
			keys[i] = new JButton[Lang[s+1+i].length];
			for (int j = 0; j < Lang[s+1+i].length; j++){
				keys[i][j] = new JButton(Lang[s+1+i+(iLang==0?0:nRow)][j]);	//创建单个按钮,按钮名@kLang[][];
				keys[i][j].setToolTipText(Lang[s+1+i+(iLang==0?nRow:0)][j]);	//光标悬停中文提示;
				keys[i][j].addActionListener(new MyKeysListen());//监听注册;动作响应@MyKeysListen();
				owner.add(keys[i][j]);           		//放置按钮@物主owner;
			}
		} 
	}
	//v0.34;20221005;将原init()中创建菜单的程序段独立为方法,便于实现中英双语界面;
	//v0.40;20221230;AWT2Swing直接升级版,并增加中文悬停提示;
	//v0.41;20230102;为新增的双语串组LANG[][]专门改写的版本;
	private void CreateMenu(JMenuBar owner,String[][] Lang,int s) {
		int nRow=Integer.parseInt(Lang[s+0][1]);		//菜单length;
		JMenu []menu = new JMenu[nRow];
		JMenuItem [][]mItem = new JMenuItem[nRow][];
		//自定义菜单监听执行动作类MyMenuListen(),事件统一响应;【核心类】
		MyMenuListen mbl = new MyMenuListen();			//创建菜单监听类实例;		
		//菜单分类创建/注册/放置;命名@MENU[][];分隔线fileMenu.addSeparator();
		for (int i = 0; i < nRow; i++){
			menu[i] = new JMenu(Lang[s+1+i+(iLang==0?0:nRow)][0]);	//创建菜单;
			menu[i].setToolTipText(Lang[s+1+i+(iLang==0?nRow:0)][0]);//光标悬停中文提示;
			menu[i].addActionListener(mbl);				//监听注册;动作响应@MyMenuListen();
			owner.add(menu[i]);           				//放置菜单@物主owner;
			mItem[i] = new JMenuItem[Lang[s+1+i].length-1];
			for (int j = 0; j < Lang[s+1+i].length-1; j++){
				mItem[i][j] = new JMenuItem(Lang[s+1+i+(iLang==0?0:nRow)][j+1]);	//创建菜单项;
				mItem[i][j].setToolTipText(Lang[s+1+i+(iLang==0?nRow:0)][j+1]);	//光标悬停中文提示;
				mItem[i][j].addActionListener(mbl);		//监听注册;动作响应@MyMenuListen();
				menu[i].add(mItem[i][j]);         		//放置菜单项;
			}
		}
	}
	//------------------------------------	
	//v0.34;初始化"关于"对话框about;v0.33新增;
	//v0.41;20230107;为新增的双语串组LANG[][]专门改写的版本;
	private void aboutInit(JFrame owner,String[][] Lang) 
  	{
		int s = classIndex("about",Lang);
		int nRow = Integer.parseInt(Lang[s+0][1]);
		int wAbout = Integer.parseInt(Lang[s+0][2]);
  	  	int hAbout = Integer.parseInt(Lang[s+0][3]);
  	  	JDialog about = new JDialog(owner,Lang[s+1+(iLang==0?0:nRow)][0],true);
  	  	JLabel 	info  = new JLabel(Lang[s+1+(iLang==0?0:nRow)][1],JLabel.CENTER);
  	  	info.setToolTipText(Lang[s+1+(iLang==0?nRow:0)][1]);//光标悬停中文提示;
  		about.setSize(wAbout,hAbout);
  		about.add(info,"Center");						//,BorderLayout.CENTER;	
  		about.setLocationRelativeTo(owner);				//位置跟随;关联frame;
  		about.setResizable(false);						//默认true;
  		about.addWindowListener(new MyWinListen());		//注册窗口监听器;MyWinListen;
  		about.setVisible(true);
  	}     
    //v0.41;20230102w1;创新的主框架初始化;为新增的双语串组LANG[][]专门改写的版本;
	private void frameInit(String[][] Lang)		
    {
    	int nRow;										//本类行数@Lang[s+0][1];
		for (int i=0;i < Lang.length; i++) {
    		switch(Lang[i][0]) {
    		case "language":
    			//iLang = (Lang[i][2]=="0"?0:1);		//默认定制;菜单切换时不需要;
    			break;	
    		case "frame":
    			nRow = Integer.parseInt(Lang[i+0][1]);
    			wFrame = Integer.parseInt(Lang[i+0][2]);
    			hFrame = Integer.parseInt(Lang[i+0][3]);
    			Image im = (new ImageIcon(Lang[i+0][4])).getImage();
    			frame = new JFrame(Lang[i+1+(iLang==0?0:nRow)][0]);	//窗口标题title;
    	    	frame.setIconImage(im);					//主窗口图标;
    			frame.setSize(wFrame+(iLang==0?0:43),hFrame);//主窗口大小;
    	    	frame.setBackground(Color.lightGray);	//自定义深蓝Color(0,64,96);推荐Color.lightGray;
    	    	frame.setLocationRelativeTo(null);		//将窗口居中;若无该方法,窗口将位于屏幕左上角;    	
    	    	//frame.setResizable(false); 			//禁止调整窗口大小。默认允许调整窗口尺寸;
    	    	break;
    		case "textshow":
    			nRow = Integer.parseInt(Lang[i+0][1]);
    			int rRow = Integer.parseInt(Lang[i+0][2]);
    			int rCol = Integer.parseInt(Lang[i+0][3]);
    			tRecord = new JTextArea(Lang[i+1+(iLang==0?0:nRow)][0],rRow,rCol);//创建文本区,操作记录显示区;
    			tRecord.setToolTipText(Lang[i+1+(iLang==0?nRow:0)][0]);	//光标悬停中文提示;
    	    	frame.add(tRecord,"West");
    	    	tResult = new JTextField(Lang[i+1+(iLang==0?0:nRow)][1],rCol);//创建单个文本行,文本名@tLang[1][];
				tResult.setToolTipText(Lang[i+1+(iLang==0?nRow:0)][1]);	//光标悬停中文提示;
    	    	frame.add(tResult,"North");
    	    	break;
    		case "pkeys":
    			JPanel pkeys = new JPanel();			//按键板;默认7行8列;
    			int kRow = Integer.parseInt(Lang[i][1]);//键组行数;
    			int kCol = Integer.parseInt(Lang[i][2]);//键组列数;
    			pkeys.setLayout(new GridLayout(kRow,kCol,1,1));	//设置布局;网格间距行列(1,1);         
    	    	CreateButtons(pkeys,Lang,i);			//创建按键板;简单DIY;
    	    	frame.add(pkeys,"East");				//顺序在前,上层优先;
    		 	break;
    		case "menu":
    	        JMenuBar mbar = new JMenuBar();
    	    	CreateMenu(mbar,Lang,i);				//创建菜单;简单DIY;   
    	    	frame.setJMenuBar(mbar);
    		}
    	}
  		frame.addWindowListener(new MyWinListen());
	    frame.setVisible(true);	
    }
    
    //构造方法:
    private Calculate() {
    	frameInit(LANG);
    }
    
    //------------------------------------
  	//v0.34;20221001;自定义菜单监听事件响应类;(监听事件响应;计算器控制主体)【核心类】	
  	class MyMenuListen implements ActionListener		//监听接口实现类;
  	{			
  		//菜单项menuItem动作响应;--接口实现方法;
  		private void ActMenu(String act) {				//菜单动作;菜单项mi;【核心方法】					
  			switch(act){		
  			case "Open"	: break;
  			case "Save"	: break;
  			case "Reset": frame.setSize(wFrame,hFrame);break;
  			case "tTip" : tResult.setText(iLang==0?"计算结果":"tResult");
  						tRecord.setText(iLang==0?"操作记录区:\n":"tRecord\n");break;
  			case "tShow": tRecord.append("\n"+"mem="+mem+"\n");
  						tRecord.append("num1+Oper+num2=tResult\n");
  						tRecord.append(num1+Oper+num2+"\n="+tResult.getText()+"\n");
  						break;
  			case "Exit"	: System.exit(0);break;
  			case "Typical": frame.setSize(wFrame-(iLang==0?132:104),hFrame);break;
  			case "Personal": frame.setSize(wFrame-(iLang==0?66:30),hFrame);break;
  			case "Multifunc": frame.setSize(wFrame+(iLang==0?132:192),hFrame);break;
  			case "Default": frame.setSize(wFrame+(iLang==0?0:43),hFrame);break;
  			case "About": aboutInit(frame,LANG);break;			
  			case "English": iLang=0;frameInit(LANG);break;	
  			case "Chinese": iLang=1;frameInit(LANG);break;
  			}	
  		}
  		//继承关系:Component.AbstractButton.MenuItem.Menu;
  		public void actionPerformed(ActionEvent e){		//执行动作(动作事件e);按钮响应;			
  			String mcmd = e.getActionCommand();			//获取动作命令;菜单命令串名@MENU[];			  			
  			//预置动作;
  			tRecord.append(mcmd);						//追加菜单操作记录;
  			if(iLang!=0)mcmd=cmdIndex(mcmd,"menu",LANG);//将非英语字串转换为英文字串;
  			//标准动作;
  			ActMenu(mcmd);								//执行菜单命令串;
  		}	
  	}
  	
  	//------------------------------------ 
	//v0.34;20221005;自定义按键监听事件响应类;(监听事件响应;计算器运行主体;)【核心类】	
	class MyKeysListen implements ActionListener {		//监听接口实现类;	

		//按键分类;--按键动作分类预处理:其它按钮无需列出;
		private final String []opNumf = {
				"0","1","2","3","4","5","6","7","8","9",
				"a","b","c","d","e","f",".",}; 			//浮点数&hex按钮;	
		private final String []opNum1 = {
				"x^2","x^3","sqrt","cbrt","1/x","n!","-/+","hex",
				"rand","sin","cos","tan","log1",}; 		//一元操作符;
		private final String []opNum2 = {"+","-","*","/","%","x^y",};//二元操作符;
		//按键动作分类方法;
		private boolean opClass(String []array, String op){	//操作动作的分类方法;串组元素确认;
			for(String element:array)if(element==op) return true;//--JDK5.0以后新增foreach语句;
			return false;
		}
		//转换整数int到16进制串;
		private String opHexStr(String []array, double num){//标准名Int2HexStr();
			String hexStr="";int d=(int)num;			//十进制d;16进制串hexStr;
			do{hexStr=opNumf[d%16]+hexStr;d/=16;}while(d!=0);
			return hexStr;
		}
		//预处理动作@1~4;
		private void ActInput(String act) {				//输入动作;分类响应的预处理方法;			
							
			if(opClass(opNumf,act)==true) {				//1.数字拼接@tfResult;					
				if(isNum==true) {
					String ts=tResult.getText();		//继续拼接;临时串ts;
					tResult.setText(ts+act);			//追加动作串act;
				}else tResult.setText(act);				//重新拼接;
				isNum=true;return;						//首位数字拼接@ks;	
			}
			if(opClass(opNum2,act)==true) {				//2.双元操作符@Oper;
				num1=Double.parseDouble(tResult.getText());	
				isNum=false;Oper=act;return;			//双元操作符@"="时延迟生效;
			}			
			if(act=="=") {								//3.等号计算;双元计算num2;				
				num2=Double.parseDouble(tResult.getText());
				isNum=false;return;							
			}
			if(opClass(opNum1,act)==true) {				//4.一元操作符;
				num1=Double.parseDouble(tResult.getText());	//转化为double;
				tRecord.append("=");	
				isNum=false;return;
			}		
		}
		//计算动作@5~7;
		private void ActCalc(String act) {				//计算动作;核心计算方法;
			
			switch(act){
			//预处理动作@1~4;
			//5.主要计算动作;
			case "hex"	:
				tResult.setText("0x"+opHexStr(opNumf,num1));break;//Int2HexStr;
			case "n!":
				int n=1;int t=(int)num1;do{n*=t--;}while(t!=1);
				tResult.setText(n+"");break;				//整数n的阶乘;
			case "cbrt"	:tResult.setText(Math.cbrt(num1)+"");break;//CubeRoot;
			case "sqrt"	:tResult.setText(Math.sqrt(num1)+"");break;//SquareRoot;
			case "x^3"	:tResult.setText(Math.pow(num1,3)+"");break;//Math.pow(a,b)取a的b次幂;				
			case "x^2"	:tResult.setText(Math.pow(num1,2)+"");break;//
			case "1/x"	:tResult.setText(1/num1+"");break;	//除0显示Infinity错误;
			case "-/+"	:tResult.setText(0-num1+"");break;	//正负转换;
			case "="	:
				switch(Oper) {								//等号操作;二元计算;
				case "+"	:tResult.setText(num1+num2+"");break;
				case "-"	:tResult.setText(num1-num2+"");break;
				case "*"	:tResult.setText(num1*num2+"");break;
				case "/"	:tResult.setText(num1/num2+"");break;
				case "%"	:tResult.setText(num1%num2+"");break;
				case "x^y"	:tResult.setText(Math.pow(num1,num2)+"");break;//Math.pow(x,y);
				}break;
			//6.辅助计算动作;
			case "M":
				if(mem==0) {
					tRecord.append("MS");				//记忆保存MS;
					mem=Double.parseDouble(tResult.getText());
				}else {
					tRecord.append("MR");				//记忆读取MR;
					tResult.setText(mem+"");isNum=true;
				}tRecord.append("\nmem="+mem+"\n");break;
			case "MC":tRecord.append("MC");mem=0;		//记忆清空MC;	
				tRecord.append("\nmem="+mem+"\n");break;							
			case "PI":tResult.setText(Math.PI+"");isNum=true;break;	//圆周率;PI=3.141592653589793-2384626;
			case "E" :tResult.setText(Math.E+"");isNum=true;break;	//Euler;E=2.718281828459045-2354;
			//7.特殊动作;
			case "BS":									//退格BackSpace;
				tResult.setText(tResult.getText().substring(0,tResult.getText().length()-1));
				break;								
			case "C":									//Copy&Clear;
				tRecord.append("\n="+tResult.getText()+"\n");//拷贝结果至记录区并换行;			
				tResult.setText("0");break;	
			case "CR" :
				num1=num2=mem=0;
				tRecord.setText("num1=num2=mem=0\n");break;	//清空记录区;			
			}		
		}
		
		//按钮动作响应;--接口方法;
		public void actionPerformed(ActionEvent e){		//执行动作(动作事件e);按钮响应;			
			String key = e.getActionCommand();			//获取按键动作命令;即按键串名key@KEYS[];			
			//预置动作;
			if(""==tResult.getText())tResult.setText("0");//避免空串赋值;	
			tRecord.append(key);						//操作动作记录;将键名追加到记录区文本;	
			if(iLang!=0)key=cmdIndex(key,"pkeys",LANG);	//将非英语字串转换为英文命令字串;
			//标准动作;
			ActInput(key);								//输入动作;				
			ActCalc(key);								//计算动作;
		}	
	}
	//------------------------------------		
	//v0.33;20221001;退窗口事件响应类;
	//exit.addActionListener(e->System.exit(0));	
	class MyWinListen extends WindowAdapter{		
		public void windowClosing(WindowEvent e){
			e.getWindow().setVisible(false);			//关闭窗口;
			e.getWindow().dispose();					//释放资源;
			if(e.getSource()==frame)
				System.exit(0);							//完全退出;
		}
	}
	//------------------------------------
	//v0.33;20221001;主方法;
	//v0.41;20230103;创新版,使用多语言数据包初始化;
    public static void main(String[] args)
    {  	
        new Calculate();								//用构造方法创建实例;主框架初始化;
    }
}

//----------------------------------------------------------------------------*/

三、运行效果:(截图)

中英文界面对比:(对话窗口自动跟随主窗口)
在这里插入图片描述

中文窗口的“语言”菜单:(多功能界面)
在这里插入图片描述
中文窗口的“帮助”菜单:(双语提示效果)
在这里插入图片描述
英文窗口中的“Option–>Typical”计算器界面:(简易型界面)
在这里插入图片描述
网页在中英文浏览器环境下的自适应显示效果:
在这里插入图片描述

Win10的显示语言包可以下载/安装/卸载:
在这里插入图片描述
IE浏览器切换使用语言@工具→Internet选项:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值