diff --git a/web/ambient/Navigator.d.ts b/web/ambient/Navigator.d.ts index ab9be528..9b3a3e47 100644 --- a/web/ambient/Navigator.d.ts +++ b/web/ambient/Navigator.d.ts @@ -1,4 +1,3 @@ interface Navigator { - msSaveOrOpenBlob: (blob: Blob ,fileName: string) => void + msSaveOrOpenBlob: (blob: Blob, fileName: string) => void } - \ No newline at end of file diff --git a/web/locales/en/translation.json b/web/locales/en/translation.json new file mode 100644 index 00000000..2758971e --- /dev/null +++ b/web/locales/en/translation.json @@ -0,0 +1,782 @@ +{ + "文档": "文档", + "账号信息": "账号信息", + "退出": "退出", + "北极星服务治理": "", + "命名空间": "", + "注册中心": "", + "服务列表": "", + "服务别名": "", + "服务网格": "", + "动态路由": "", + "自定义路由": "", + "测试环境路由": "", + "灰度发布": "", + "熔断降级": "", + "访问限流": "", + "配置中心": "", + "配置分组": "配置分组", + "发布历史": "", + "可观测性": "", + "注册配置监控": "", + "流量监控": "", + "权限控制": "", + "用户": "", + "用户组": "", + "策略": "", + "多个请求匹配规则之间是且的关系": "多个请求匹配规则之间是且的关系", + "部分匹配运算符的说明如下:": "部分匹配运算符的说明如下:", + "包含:多字符串取OR匹配,传入的值只要匹配到其中一个字符串,就算匹配成功。字符串之间使用逗号进行分割。值格式为'value1,value2,value3‘,匹配到其中一个就算成功。": "包含:多字符串取OR匹配,传入的值只要匹配到其中一个字符串,就算匹配成功。字符串之间使用逗号进行分割。值格式为'value1,value2,value3‘,匹配到其中一个就算成功。", + "不包含:多字符串取反匹配,传入的值必须都没有出现在所配置的字符串列表中,才算匹配通过。值格式为'value1,value2,value3‘,全部不等于才算成功。": "不包含:多字符串取反匹配,传入的值必须都没有出现在所配置的字符串列表中,才算匹配通过。值格式为'value1,value2,value3‘,全部不等于才算成功。", + "限流规则名称": "", + "限流类型": "", + "限流规则详情": "", + "目标服务": "", + "您可以对目标服务的指定接口设置限流规则。当该接口被调用时,符合匹配规则的请求,则会触发限流规则": "", + "服务名称": "", + "接口名称": "", + "请求匹配规则": "", + "类型": "", + "限流规则": "", + "限流条件": "限流条件", + "满足以下任意条件即可触发限流": "满足以下任意条件即可触发限流", + "限流阈值": "", + "统计窗口时长": "", + "请求数阈值": "", + "次": "", + "合并计算阈值": "", + "如果目标请求匹配到多个接口及参数,则将匹配到的所有请求汇合,合并计算阈值,具体规则查看": "", + "是": "", + "否": "", + "限流方案": "限流方案", + "满足限流触发条件后的处理方案": "满足限流触发条件后的处理方案", + "限流效果": "", + "失败处理策略": "", + "当出现通信失败或者 Token Server 不可用时,限流方案退化到单机限流的模式": "", + "最大排队时长": "", + "秒": "", + "是否启用": "", + "ID/规则名": "", + "状态": "", + "已启用": "", + "未启用": "", + "创建时间/修改时间": "", + "启用时间": "", + "操作": "", + "禁用": "", + "启用": "", + "编辑": "", + "删除": "", + "请选择命名空间": "", + "请输入Key值": "", + "请选择服务名": "", + "请输入Value值": "", + "编辑服务限流规则": "", + "新建服务限流规则": "", + "最长64个字符": "", + "没有匹配的服务名称": "", + "请输入接口名称,默认全选": "", + "添加": "添加", + "删除所有": "删除所有", + "提交": "提交", + "取消": "取消", + "请填写限流规则名称": "", + "请选择类型": "", + "请输入IP": "", + "请输入value值": "", + "请输入key值": "", + "新建限流规则": "新建限流规则", + "请输入规则名过滤": "", + "全部": "", + "确认删除限流规则 {{attr0}} 吗?": "", + "删除后,无法恢复": "", + "确认{{attr0}}限流规则 {{attr1}} 吗?": "", + "单机限流": "", + "分布式限流": "", + "快速失败": "", + "匀速排队": "", + "全匹配": "", + "正则表达式": "", + "不等于": "", + "包含": "", + "不包含": "", + "自定义": "", + "请求头(HEADER)": "", + "请求参数(QUERY)": "", + "方法(METHOD)": "", + "主调服务": "", + "主调IP": "", + "退化至单机限流": "", + "直接通过": "", + "分钟": "", + "小时": "", + "服务": "", + "接口": "", + "编辑主动探测规则": "", + "新建主动探测规则": "新建主动探测规则", + "规则名称": "", + "描述": "", + "全部命名空间": "", + "全部服务": "", + "(输入值){{attr0}}": "", + "请输入接口名称": "", + "周期": "", + "超时时间": "", + "端口": "", + "协议": "", + "服务实例下需要存在所选择用于探测的协议,否则无法探测无法生效": "", + "方法": "", + "请输入url 以/开头": "", + "header键": "", + "header值": "", + "请填写规则名称": "", + "名称只能含有数字,字母,下划线及中划线": "", + "请输入超时时间": "", + "请输入url": "", + "请输入键": "", + "请输入值": "", + "规则名": "", + "目标命名空间": "", + "目标方法": "", + "请选择条件进行过滤": "", + "确认删除规则 {{attr0}} 吗?": "", + "命名空间:": "命名空间:", + "服务:": "服务:", + "被调服务": "", + "接口:": "接口:", + "编辑熔断规则": "", + "新建熔断规则": "", + "匹配条件": "", + "熔断配置": "", + "错误判断条件": "", + "满足以下任意应答条件的请求会被标识为错误请求": "满足以下任意应答条件的请求会被标识为错误请求", + "超过": "", + "毫秒": "", + "熔断触发条件": "熔断触发条件", + "满足以下任意条件可触发熔断": "满足以下任意条件可触发熔断", + "统计周期": "", + "最小请求数": "", + "个": "", + "熔断粒度": "", + "熔断触发时影响的资源粒度": "熔断触发时影响的资源粒度", + "熔断恢复": "熔断恢复", + "经过熔断时长后,会触发熔断恢复机制,若符合预期,则结束熔断;否则重新回到熔断阶段": "经过熔断时长后,会触发熔断恢复机制,若符合预期,则结束熔断;否则重新回到熔断阶段", + "熔断时长": "", + "熔断恢复策略": "", + "当满足": "当满足", + "个连续成功请求后恢复": "个连续成功请求后恢复", + "主动探测": "", + "开启主动探测时,客户端将会根据您配置的探测规则对目标被调服务进行探测; 主动探测请求与业务调用合并判断熔断恢复(如未匹配到探测规则,则不会生效); 未开启主动探测时,会仅根据业务调用判断熔断恢复。": "开启主动探测时,客户端将会根据您配置的探测规则对目标被调服务进行探测; 主动探测请求与业务调用合并判断熔断恢复(如未匹配到探测规则,则不会生效); 未开启主动探测时,会仅根据业务调用判断熔断恢复。", + "查看主动探测规则": "查看主动探测规则", + "熔断后降级": "", + "自定义响应": "", + "熔断触发后的降级响应策略": "熔断触发后的降级响应策略", + "返回码": "", + "是否开启": "", + "请填写路由规则名称": "", + "请输入接口名": "", + "请输入条件": "", + "请选择熔断粒度": "", + "源命名空间": "", + "源服务": "", + "% (统计周期:": "% (统计周期:", + ",最小请求数:": ",最小请求数:", + "{{attr0}}秒": "", + "恢复策略": "", + "开启": "", + "关闭": "", + "消息头": "", + "消息体": "", + "未开启": "", + "确认{{attr0}}规则 {{attr1}} 吗?": "", + "时延": "", + "连续错误数": "", + "错误率": "", + "实例": "", + "实例分组": "实例分组", + "服务级熔断": "", + "节点级熔断": "", + "优先级": "", + "主调请求按照匹配规则匹配成功后,将按照当前规则进行目标服务路由": "主调请求按照匹配规则匹配成功后,将按照当前规则进行目标服务路由", + "请求会按照规则路由到目标服务分组": "请求会按照规则路由到目标服务分组", + "路由策略": "", + "规则{{attr0}}": "", + "来源服务的请求满足以下匹配条件": "来源服务的请求满足以下匹配条件", + "键": "", + "匹配方式": "", + "值": "", + "将转发至目标服务的以下实例分组": "将转发至目标服务的以下实例分组", + "实例标签": "", + "权重": "", + "是否隔离": "", + "命名空间:": "命名空间:", + "服务:": "服务:", + "没有匹配的标签键": "", + "请输入标签键": "", + "没有匹配的标签值": "", + "请输入标签值": "", + "请输入完整标签": "", + "确认": "", + "编辑服务路由规则": "", + "新建服务路由规则": "", + "点击切换主被调服务": "点击切换主被调服务", + "将转发至目标服务的一下实例分组": "将转发至目标服务的一下实例分组", + "相对权重,数值范围:0-65535": "", + "添加规则": "添加规则", + "优先级数字设置越小,匹配顺序越靠前": "", + "请输入标签分组": "", + "规则1": "", + "主调命名空间": "", + "被调命名空间": "", + "新建路由规则": "", + "确认删除路由规则 {{attr0}} 吗?": "", + "确认{{attr0}}路由规则 {{attr1}} 吗?": "", + "等于": "", + "正则表达式匹配": "", + "范围表达式": "", + "变量": "", + "请求Cookie(COOKIE)": "", + "路径": "", + "操作指引": "操作指引", + "蓝绿发布": "", + "金丝雀发布": "", + "全链路灰度发布": "", + "蓝绿发布路由": "", + "金丝雀发布路由": "", + "针对是单个服务的服务灰度验证,金丝雀发布允许引流一小部分流量到服务的新版本(比如按灰度用户引流),充分验证微服务新版本的稳定性,验证没问题后,再升级原来的稳定版本。": "", + "场景一": "", + "场景二": "", + "微服务架构下,有些开发需求,微服务调用链路上的多个微服务同时发生了改动, 通常每个微服务都会有灰度环境或分组来接收灰度流量。此时希望通过进入上游灰度环境的流量, 也能进入下游灰度的环境中,确保1个请求始终在灰度环境中传递,即使这个调用链路上有一些微服务没有灰度环境, 这些应用请求在下游的时候依然能够回到灰度环境中。": "微服务架构下,有些开发需求,微服务调用链路上的多个微服务同时发生了改动, 通常每个微服务都会有灰度环境或分组来接收灰度流量。此时希望通过进入上游灰度环境的流量, 也能进入下游灰度的环境中,确保1个请求始终在灰度环境中传递,即使这个调用链路上有一些微服务没有灰度环境, 这些应用请求在下游的时候依然能够回到灰度环境中。", + "实现方案的两个场景:": "实现方案的两个场景:", + "应用场景一:金丝雀环境和稳定环境有独立的域名进行隔离,实现全链路灰度。": "应用场景一:金丝雀环境和稳定环境有独立的域名进行隔离,实现全链路灰度。", + "应用场景二:使用相同域名,基于请求标签实现全链路灰度。": "应用场景二:使用相同域名,基于请求标签实现全链路灰度。", + "客户端染色": "", + "网关动态染色": "", + "网关静态染色": "", + "客户端染色流程指引": "", + "网关动态染色流程指引": "", + "网关静态染色流程指引": "", + "告警策略名称": "", + "启用状态": "", + "监控类型": "", + "更新时间": "", + "触发条件": "", + "持续": "持续", + "告警周期": "", + "每隔": "每隔", + "告警一次": "告警一次", + "告警主题": "", + "通知回调地址": "", + "策略ID/名称": "", + "告警规则": "", + "创建时间": "", + "编辑告警策略": "", + "新建告警策略": "", + "名字": "", + "当": "", + "持续时间": "", + "告警消息": "", + "请填写名称": "", + "请填写监控类型": "", + "请选择请求指标": "", + "请选择表达式": "", + "请选择阈值": "", + "请输入持续时长": "", + "请选择持续时长单位": "", + "请选择告警周期": "", + "请输入告警主题": "", + "请输入告警消息": "", + "业务监控": "", + "监控曲线": "", + "环比波动": "", + "环比上升": "", + "环比下降": "", + "天": "", + "服务发现连接数": "", + "配置获取连接数": "", + "客户端数": "", + "每1分钟告警一次": "", + "每5分钟告警一次": "", + "每15分钟告警一次": "", + "每1小时告警一次": "", + "每4小时告警一次": "", + "每天告警一次": "", + "名称": "", + "所有命名空间": "", + "所有服务": "", + "所有配置分组": "", + "权限": "", + "读|写": "", + "权限策略": "", + "可操作资源": "", + "License已超过最大过期时间": "", + "北极星服务治理中心": "北极星服务治理中心", + "一个支持多语言、多框架和异构基础设施的服务治理中心,提供服务发现、流量调度、熔断降级、限流鉴权和可观测性等服务治理功能。北极星治理中心默认提供服务注册功能,也可以搭配其他服务注册中心使用。": "一个支持多语言、多框架和异构基础设施的服务治理中心,提供服务发现、流量调度、熔断降级、限流鉴权和可观测性等服务治理功能。北极星治理中心默认提供服务注册功能,也可以搭配其他服务注册中心使用。", + "登录": "登录", + "外网访问建议设置访问控制策略": "外网访问建议设置访问控制策略", + "初始用户名和密码为": "初始用户名和密码为", + "用户名": "", + "密码": "", + "网络异常或用户名,密码错误": "", + "请输入用户名": "", + "请输入密码": "", + "选择用户": "", + "授权": "", + "预览": "", + "编辑策略": "", + "创建策略": "", + "备注": "", + "角色": "", + "请选择用户": "", + "请选择用户组": "", + "默认策略不可变更授权角色": "", + "资源": "", + "全部命名空间(含后续新增)": "", + "指定命名空间": "", + "全部服务(含后续新增)": "", + "指定服务": "", + "请选择服务": "", + "全部配置分组(含后续新增)": "", + "指定配置分组": "", + "请选择配置分组": "", + "读操作|写操作": "", + "策略名称": "", + "无选中用户": "", + "无选中用户组": "", + "完成": "", + "下一步": "", + "上一步": "", + "编辑成功": "", + "编辑失败": "", + "创建成功": "", + "创建失败": "", + "请输入名称": "", + "只能使用中文、数字、大小写字母 以及- _组成": "", + "最大长度为64": "", + "{{attr0}}({{attr1}})": "", + "(用户组)": "", + "(用户)": "", + "新建策略": "", + "默认策略(": "默认策略(", + "自定义策略(": "自定义策略(", + "无备注": "", + "用户|用户组": "", + "暂无对应授权对象": "", + "全部{{attr0}}(含后续新增)": "", + "暂无选中策略": "", + "确认删除如下策略?": "", + "删除后,策略不可用且无法恢复": "", + "删除成功": "", + "删除失败": "", + "用户详情({{attr0}})": "", + "用户信息": "", + "修改密码": "", + "账号名": "", + "账号ID": "", + "手机号": "", + "邮箱": "", + "生效中": "", + "已失效": "", + "重置": "", + "仅主账号可查看Token": "", + "修改成功": "", + "修改失败": "", + "{{attr0}}成功": "", + "{{attr0}}失败": "", + "重置成功": "", + "您已成功重置Token,请重新登录。": "", + "重置失败": "", + "(当前登录)": "", + "用户类型": "", + "主账号": "", + "子账号": "", + "用户id": "", + "查看Token": "", + "更多": "", + "关联用户组": "", + "确定": "确定", + "授权策略": "", + "请选择策略": "", + "未做改动": "", + "请输入6至17位的密码": "", + "编辑用户": "", + "新建用户": "", + "旧密码": "", + "如果您忘记了您的旧密码,可以联系您的主账号来重置密码": "", + "新密码": "", + "确认密码": "", + "修改密码成功": "", + "您已成功重置密码,请重新登录。": "", + "修改密码失败": "", + "请输入旧密码": "", + "请输入新密码": "", + "请确认密码": "", + "两次输入密码不一致": "", + "修改备注": "", + "请输入备注": "", + "授予权限的用户或者用户组,具有该命名空间的读写权限,所有用户具有读权限": "", + "支持按住shift进行多选": "", + "新建": "新建", + "编辑用户组": "", + "确认删除用户?": "", + "删除后,用户不可用且无法恢复": "", + "查看{{attr0}}的token": "", + "用户组详情({{attr0}})": "", + "用户组名": "", + "用户组ID": "", + "用户组名称": "", + "用户数量": "", + "新建用户组": "", + "关联成功": "", + "确认删除用户组?": "", + "删除后,用户组不可用且无法恢复": "", + "因为浏览器限制,此文件仅保存了部分内容": "", + "标签键": "", + "标签值": "", + "暂无标签": "", + "请输入完整键值对": "", + "编辑器正在加载中": { + "": "" + }, + "排序": "", + "标签名": "", + "key 最长不超过128个字符": "", + "value 最长不超过4096个字符": "", + "新增": "新增", + "近24小时": "", + "近3天": "", + "近7天": "", + "加载中": "", + "未找到指定资源,请检查资源是否存在": "", + "设置成功": "", + "请选择您想显示的列表详细信息。": "", + "根据您的分辨率,最多可勾选{{attr0}}个字段,已勾选{{attr1}}个。": "", + "自定义列表字段": "", + "请选择": "", + "加载失败": "", + "输入关键字搜索": "", + "暂无数据": "", + "找到{{attr0}}条结果": "", + "搜索\"{{attr0}}\"暂无数据": "", + "已选择 ({{attr0}})": "", + "提交失败": "", + "[deprecated] 建议使用对象递归,而不在返回值内递归": "", + "当前导出进度:{{attr0}}%": "", + "此浏览器版本过低,不支持导出功能": "", + "因文件过大,自动拆分为多个文件下载": "", + "导出成功": "", + "导出失败": "", + "请求错误": "", + "发布成功": "", + "发布失败": "", + "编辑待发布": "", + "历史发布": "历史发布", + "当前发布": "当前发布", + "编辑配置文件": "", + "新建配置文件": "", + "配置文件名": "", + "可通过/分隔符创建文件夹,强烈建议文件名带上后缀,如:datasource/master": { + "json": "" + }, + "文件格式: ": "", + "允许数字、英文字母、": { + "、-、_,限制128个字符": "" + }, + "长度不超过1024个字符": "", + "配置标签": "", + "该配置分组为只读配置分组": "", + "该命名空间为只读命名空间": "", + "请填写文件名": "", + "文件夹名字不可为空": "", + "请选择分组": "", + "请选择格式": "", + "应用模板": "应用模板", + "应用": "", + "模板": "", + "提供常用的配置文件模板,以方便进行快速配置": "", + "当前选择的模板与配置文件格式不符": "", + "模板格式": "", + "模板描述": "", + "模板预览": "", + "请确认应用模板": "", + "应用所选模板将会覆盖当前已编辑的内容": "", + "您当前选择的模板与配置文件格式不符,请检查后重试。": "", + "刷新成功": "", + "刷新配置": "刷新配置", + "提示": "", + "注意,刷新会导致丢失当前编辑内容": "注意,刷新会导致丢失当前编辑内容", + "请输入文件名搜索": "", + "查看发布历史": "查看发布历史", + "最后修改时间": "", + "最后发布时间": "", + "标签": "", + "最后修改人": "", + "最后发布人": "", + "格式": "", + "发布": "发布", + "保存": "保存", + "版本": "", + "发布时间": "", + "请选择发布记录": "请选择发布记录", + "未搜索到对应文件": "未搜索到对应文件", + "待发布": "待发布", + "确认删除配置文件?": "", + "删除后,无法恢复。": "", + "确认切换展示节点?": "", + "编辑未发布,现在切换将丢失已编辑内容": "", + "内容对比": "", + "保存成功": "", + "保存失败": "", + "配置文件": "", + "配置文件数": "", + "无权限": "", + "编辑配置文件组": "", + "新建配置文件组": "", + "分组名": "", + "高级配置": "高级配置", + "请填写分组名": "", + "请填写命名空间": "", + "确认删除配置组": "", + "删除配置组也会同时删除配置组下所有配置文件,请谨慎删除。": "", + "操作人": "", + "查看详情": "", + "分组": "", + "近1小时": "", + "近1天": "", + "近1周": "", + "新建监控图表": "", + "时间选择": "", + "指标名": "", + "筛选条件": "", + "条件": "", + "条件值": "", + "步长": "步长", + "主调方": "主调方", + "主调": "", + "汇总": "", + "被调方": "被调方", + "被调": "", + "查询": "查询", + "暂无图表数据": "", + "复制分享链接": "复制分享链接", + "保存当前配置": "保存当前配置", + "载入保存配置": "载入保存配置", + "筛选条件:": "筛选条件:", + "{{attr0}}\n :{{attr1}} ;": "", + "无": "", + "路由监控": "", + "熔断监控": "", + "限流监控": "", + "监控": "", + "本次筛选配置将会请求大量数据": "", + "请确认是否请求": "", + "已保存": "", + "客户端节点数": "", + "客户端连接数": "", + "总请求数": "", + "客户端访问北极星服务端请求数": "客户端访问北极星服务端请求数", + "请求时延": "", + "客户端访问北极星服务端请求时延": "客户端访问北极星服务端请求时延", + "服务数": "", + "实例数": "", + "配置分组数": "", + "配置数": "", + "概览": "", + "服务和配置统计": "", + "北极星服务端请求统计": "", + "1秒": "", + "1分": "", + "5分": "", + "1小时": "", + "全部命名空间汇总": "", + "时间范围": "", + "时间粒度": "", + "功能": "", + "全部功能汇总": "", + "全部接口汇总": "", + "无可选接口": "无可选接口", + "节点": "", + "全部节点汇总": "", + "无节点": "无节点", + "请求数": "", + "失败请求数": "", + "返回码分布": "", + "所有接口汇总-": "", + "所有节点汇总": "", + "{{attr0}}功能-{{attr1}}接口": "", + "所有接口汇总": "", + "{{attr0}}节点": "", + "全部汇总服务": "", + "无可选服务": "无可选服务", + "全部配置分组汇总": "", + "无配置分组": "无配置分组", + "总节点数": "", + "总连接数": "", + "注册中心连接数": "", + "配置中心连接数": "", + "成功请求数": "", + "请求成功率": "", + "均值": "", + "最大值": "", + "最小值": "", + "总服务数": "", + "在线服务数": "", + "异常服务数": "", + "离线服务数": "", + "总实例数": "", + "在线实例数": "", + "隔离实例数": "", + "异常实例数": "", + "配置分组总数": "", + "已发布配置文件数": "", + "总失败请求数": "", + "5xx失败请求数": "", + "4xx失败请求数": "", + "网络失败数": "", + "服务注册": "", + "服务发现": "", + "健康检查": "", + "配置读取": "", + "成功数": "", + "最大时延": "", + "平均时延": "", + "通过数": "", + "限流数": "", + "熔断数": "", + "半开数": "", + "被调服务名": "", + "被调接口名": "", + "被调实例分组": "", + "被调实例": "", + "被调请求标签": "", + "主调服务名": "", + "主调实例IP": "", + "主调请求标签": "", + "健康实例/总实例数": "", + "修改时间": "", + "编辑命名空间": "", + "新建命名空间": "", + "高级设置": "", + "请输入命名空间名称": "", + "确认删除命名空间": "", + "服务名": "", + "接口名": "", + "{{attr0}}({{attr1}}匹配)": "", + "该命名空间为只读的": "", + "无写权限": "", + "在该规则前新建规则": "", + "正则模式下,使用*代表选择所有": "", + "手动配置": "", + "JSON配置": "", + "以下服务": "", + "本服务调用以下服务或者接口时": "", + "调用本服务的以下接口时": "", + "如果满足以下任意条件,进行熔断": "如果满足以下任意条件,进行熔断", + "最大响应时间": "", + "半开时间": "", + "编辑方式": "", + "JSON编辑": "", + "请输入正确的JSON字符串": "", + "请输入命名空间": "", + "请输入服务名": "", + "编辑格式": "", + "规则类型": "", + "未更改": "", + "向服务器端提交变更": "", + "当以下服务调用本服务时,遵守下列熔断规则": "", + "当本服务调用以下服务时,遵守下列熔断规则": "", + "如果请求标签匹配,按以下策略熔断": "", + "熔断条件": "", + "当请求个数大于{{attr0}}个,且{{attr1}}大于{{attr2}}%时熔断": "", + "以超过{{attr0}}的请求作为超时请求,{{attr1}}大于{{attr2}}%时熔断": "", + "当连续请求错误超过{{attr0}}个时熔断": "", + "编辑规则": "", + "确认删除规则": "", + "连续错误率": "", + "精确": "", + "正则": "", + "被调规则": "", + "主调规则": "", + "仅用于恢复": "", + "用于熔断和恢复": "", + "部门": "", + "业务": "", + "版本号": "", + "服务标签({{attr0}}个)": "", + "就近访问": "", + "实例IP": "", + "健康状态": "", + "隔离状态": "", + "地区/地域/可用区": "", + "编辑服务实例": "", + "新建服务实例": "", + "隔离状态下,主调方无法发现隔离的服务实例,无论实例IP是否健康": "", + "多个IP以英文逗号、英文分号、空格或换行分隔,每次最多添加100个IP": "", + "多个端口以英文逗号、英文分号、空格或换行分隔,每次最多添加100个端口": "", + "实例标签可用于标识实例的用处、特征, 标签数量不能超过64": "", + "地域信息": "", + "请输入 Region": "", + "请输入 Zone": "", + "请输入 Campus": "", + "开启健康检查": "开启健康检查", + "如果开启,服务端负责检查服务实例的健康状态": "", + "健康检查方式": "", + "检查方式": "", + "请填写IP": "", + "请填写端口": "", + "请填写权重": "", + "请选择检查方式": "", + "请填写TTL": "", + "请选择实例": "", + "其他操作": "其他操作", + "复制IP": "复制IP", + "修改权重": "修改权重", + "修改健康状态": "修改健康状态", + "修改隔离状态": "修改隔离状态", + "实例ID": "", + "检查方式:": "检查方式:", + "; TTL:": "; TTL:", + "展示全部": "展示全部", + "确认删除实例": "", + "心跳上报": "", + "健康": "", + "异常": "", + "隔离": "", + "不隔离": "", + "请求标签": "", + "当以下服务调用本服务时": "", + "当本服务调用以下服务时": "", + "对带有以下标签的请求": "对带有以下标签的请求", + "按权重和优先级路由到以下实例分组": "按权重和优先级路由到以下实例分组", + "标签键不能为空": "", + "标签值不能为空": "", + "标签键不能一致": "", + "新建一条规则": "", + "当以下服务调用本服务时,遵守下列路由规则": "", + "当本服务调用以下服务时,遵守以下路由规则": "", + "如果请求标签匹配,按权重和优先级路由到以下实例分组": "", + "实例分组{{attr0}}": "", + "编辑路由规则": "", + "确认删除路由规则": "", + "图表编辑": "", + "服务信息": "", + "服务实例": "", + "路由规则": "", + "熔断规则": "", + "编辑服务": "", + "新建服务": "", + "开启就近访问": "", + "服务标签": "", + "服务标签可用于标识服务的用处、特征,格式为key:value": "", + "长度不超过1024个字符,标签数量不能超过64个": "", + "确认删除服务": "", + "标签展示": "", + "指向服务": "", + "别名所在命名空间": "", + "请选择指向服务": "", + "请选择别名所在命名空间": "", + "请填写别名": "", + "服务别名可以看作是服务的映射,访问服务别名等同于访问服务,允许多个服务别名指向同一个服务": "服务别名可以看作是服务的映射,访问服务别名等同于访问服务,允许多个服务别名指向同一个服务", + "新建别名": "", + "确认删除服务别名": "" +} diff --git a/web/locales/fr/translation.json b/web/locales/fr/translation.json new file mode 100644 index 00000000..2758971e --- /dev/null +++ b/web/locales/fr/translation.json @@ -0,0 +1,782 @@ +{ + "文档": "文档", + "账号信息": "账号信息", + "退出": "退出", + "北极星服务治理": "", + "命名空间": "", + "注册中心": "", + "服务列表": "", + "服务别名": "", + "服务网格": "", + "动态路由": "", + "自定义路由": "", + "测试环境路由": "", + "灰度发布": "", + "熔断降级": "", + "访问限流": "", + "配置中心": "", + "配置分组": "配置分组", + "发布历史": "", + "可观测性": "", + "注册配置监控": "", + "流量监控": "", + "权限控制": "", + "用户": "", + "用户组": "", + "策略": "", + "多个请求匹配规则之间是且的关系": "多个请求匹配规则之间是且的关系", + "部分匹配运算符的说明如下:": "部分匹配运算符的说明如下:", + "包含:多字符串取OR匹配,传入的值只要匹配到其中一个字符串,就算匹配成功。字符串之间使用逗号进行分割。值格式为'value1,value2,value3‘,匹配到其中一个就算成功。": "包含:多字符串取OR匹配,传入的值只要匹配到其中一个字符串,就算匹配成功。字符串之间使用逗号进行分割。值格式为'value1,value2,value3‘,匹配到其中一个就算成功。", + "不包含:多字符串取反匹配,传入的值必须都没有出现在所配置的字符串列表中,才算匹配通过。值格式为'value1,value2,value3‘,全部不等于才算成功。": "不包含:多字符串取反匹配,传入的值必须都没有出现在所配置的字符串列表中,才算匹配通过。值格式为'value1,value2,value3‘,全部不等于才算成功。", + "限流规则名称": "", + "限流类型": "", + "限流规则详情": "", + "目标服务": "", + "您可以对目标服务的指定接口设置限流规则。当该接口被调用时,符合匹配规则的请求,则会触发限流规则": "", + "服务名称": "", + "接口名称": "", + "请求匹配规则": "", + "类型": "", + "限流规则": "", + "限流条件": "限流条件", + "满足以下任意条件即可触发限流": "满足以下任意条件即可触发限流", + "限流阈值": "", + "统计窗口时长": "", + "请求数阈值": "", + "次": "", + "合并计算阈值": "", + "如果目标请求匹配到多个接口及参数,则将匹配到的所有请求汇合,合并计算阈值,具体规则查看": "", + "是": "", + "否": "", + "限流方案": "限流方案", + "满足限流触发条件后的处理方案": "满足限流触发条件后的处理方案", + "限流效果": "", + "失败处理策略": "", + "当出现通信失败或者 Token Server 不可用时,限流方案退化到单机限流的模式": "", + "最大排队时长": "", + "秒": "", + "是否启用": "", + "ID/规则名": "", + "状态": "", + "已启用": "", + "未启用": "", + "创建时间/修改时间": "", + "启用时间": "", + "操作": "", + "禁用": "", + "启用": "", + "编辑": "", + "删除": "", + "请选择命名空间": "", + "请输入Key值": "", + "请选择服务名": "", + "请输入Value值": "", + "编辑服务限流规则": "", + "新建服务限流规则": "", + "最长64个字符": "", + "没有匹配的服务名称": "", + "请输入接口名称,默认全选": "", + "添加": "添加", + "删除所有": "删除所有", + "提交": "提交", + "取消": "取消", + "请填写限流规则名称": "", + "请选择类型": "", + "请输入IP": "", + "请输入value值": "", + "请输入key值": "", + "新建限流规则": "新建限流规则", + "请输入规则名过滤": "", + "全部": "", + "确认删除限流规则 {{attr0}} 吗?": "", + "删除后,无法恢复": "", + "确认{{attr0}}限流规则 {{attr1}} 吗?": "", + "单机限流": "", + "分布式限流": "", + "快速失败": "", + "匀速排队": "", + "全匹配": "", + "正则表达式": "", + "不等于": "", + "包含": "", + "不包含": "", + "自定义": "", + "请求头(HEADER)": "", + "请求参数(QUERY)": "", + "方法(METHOD)": "", + "主调服务": "", + "主调IP": "", + "退化至单机限流": "", + "直接通过": "", + "分钟": "", + "小时": "", + "服务": "", + "接口": "", + "编辑主动探测规则": "", + "新建主动探测规则": "新建主动探测规则", + "规则名称": "", + "描述": "", + "全部命名空间": "", + "全部服务": "", + "(输入值){{attr0}}": "", + "请输入接口名称": "", + "周期": "", + "超时时间": "", + "端口": "", + "协议": "", + "服务实例下需要存在所选择用于探测的协议,否则无法探测无法生效": "", + "方法": "", + "请输入url 以/开头": "", + "header键": "", + "header值": "", + "请填写规则名称": "", + "名称只能含有数字,字母,下划线及中划线": "", + "请输入超时时间": "", + "请输入url": "", + "请输入键": "", + "请输入值": "", + "规则名": "", + "目标命名空间": "", + "目标方法": "", + "请选择条件进行过滤": "", + "确认删除规则 {{attr0}} 吗?": "", + "命名空间:": "命名空间:", + "服务:": "服务:", + "被调服务": "", + "接口:": "接口:", + "编辑熔断规则": "", + "新建熔断规则": "", + "匹配条件": "", + "熔断配置": "", + "错误判断条件": "", + "满足以下任意应答条件的请求会被标识为错误请求": "满足以下任意应答条件的请求会被标识为错误请求", + "超过": "", + "毫秒": "", + "熔断触发条件": "熔断触发条件", + "满足以下任意条件可触发熔断": "满足以下任意条件可触发熔断", + "统计周期": "", + "最小请求数": "", + "个": "", + "熔断粒度": "", + "熔断触发时影响的资源粒度": "熔断触发时影响的资源粒度", + "熔断恢复": "熔断恢复", + "经过熔断时长后,会触发熔断恢复机制,若符合预期,则结束熔断;否则重新回到熔断阶段": "经过熔断时长后,会触发熔断恢复机制,若符合预期,则结束熔断;否则重新回到熔断阶段", + "熔断时长": "", + "熔断恢复策略": "", + "当满足": "当满足", + "个连续成功请求后恢复": "个连续成功请求后恢复", + "主动探测": "", + "开启主动探测时,客户端将会根据您配置的探测规则对目标被调服务进行探测; 主动探测请求与业务调用合并判断熔断恢复(如未匹配到探测规则,则不会生效); 未开启主动探测时,会仅根据业务调用判断熔断恢复。": "开启主动探测时,客户端将会根据您配置的探测规则对目标被调服务进行探测; 主动探测请求与业务调用合并判断熔断恢复(如未匹配到探测规则,则不会生效); 未开启主动探测时,会仅根据业务调用判断熔断恢复。", + "查看主动探测规则": "查看主动探测规则", + "熔断后降级": "", + "自定义响应": "", + "熔断触发后的降级响应策略": "熔断触发后的降级响应策略", + "返回码": "", + "是否开启": "", + "请填写路由规则名称": "", + "请输入接口名": "", + "请输入条件": "", + "请选择熔断粒度": "", + "源命名空间": "", + "源服务": "", + "% (统计周期:": "% (统计周期:", + ",最小请求数:": ",最小请求数:", + "{{attr0}}秒": "", + "恢复策略": "", + "开启": "", + "关闭": "", + "消息头": "", + "消息体": "", + "未开启": "", + "确认{{attr0}}规则 {{attr1}} 吗?": "", + "时延": "", + "连续错误数": "", + "错误率": "", + "实例": "", + "实例分组": "实例分组", + "服务级熔断": "", + "节点级熔断": "", + "优先级": "", + "主调请求按照匹配规则匹配成功后,将按照当前规则进行目标服务路由": "主调请求按照匹配规则匹配成功后,将按照当前规则进行目标服务路由", + "请求会按照规则路由到目标服务分组": "请求会按照规则路由到目标服务分组", + "路由策略": "", + "规则{{attr0}}": "", + "来源服务的请求满足以下匹配条件": "来源服务的请求满足以下匹配条件", + "键": "", + "匹配方式": "", + "值": "", + "将转发至目标服务的以下实例分组": "将转发至目标服务的以下实例分组", + "实例标签": "", + "权重": "", + "是否隔离": "", + "命名空间:": "命名空间:", + "服务:": "服务:", + "没有匹配的标签键": "", + "请输入标签键": "", + "没有匹配的标签值": "", + "请输入标签值": "", + "请输入完整标签": "", + "确认": "", + "编辑服务路由规则": "", + "新建服务路由规则": "", + "点击切换主被调服务": "点击切换主被调服务", + "将转发至目标服务的一下实例分组": "将转发至目标服务的一下实例分组", + "相对权重,数值范围:0-65535": "", + "添加规则": "添加规则", + "优先级数字设置越小,匹配顺序越靠前": "", + "请输入标签分组": "", + "规则1": "", + "主调命名空间": "", + "被调命名空间": "", + "新建路由规则": "", + "确认删除路由规则 {{attr0}} 吗?": "", + "确认{{attr0}}路由规则 {{attr1}} 吗?": "", + "等于": "", + "正则表达式匹配": "", + "范围表达式": "", + "变量": "", + "请求Cookie(COOKIE)": "", + "路径": "", + "操作指引": "操作指引", + "蓝绿发布": "", + "金丝雀发布": "", + "全链路灰度发布": "", + "蓝绿发布路由": "", + "金丝雀发布路由": "", + "针对是单个服务的服务灰度验证,金丝雀发布允许引流一小部分流量到服务的新版本(比如按灰度用户引流),充分验证微服务新版本的稳定性,验证没问题后,再升级原来的稳定版本。": "", + "场景一": "", + "场景二": "", + "微服务架构下,有些开发需求,微服务调用链路上的多个微服务同时发生了改动, 通常每个微服务都会有灰度环境或分组来接收灰度流量。此时希望通过进入上游灰度环境的流量, 也能进入下游灰度的环境中,确保1个请求始终在灰度环境中传递,即使这个调用链路上有一些微服务没有灰度环境, 这些应用请求在下游的时候依然能够回到灰度环境中。": "微服务架构下,有些开发需求,微服务调用链路上的多个微服务同时发生了改动, 通常每个微服务都会有灰度环境或分组来接收灰度流量。此时希望通过进入上游灰度环境的流量, 也能进入下游灰度的环境中,确保1个请求始终在灰度环境中传递,即使这个调用链路上有一些微服务没有灰度环境, 这些应用请求在下游的时候依然能够回到灰度环境中。", + "实现方案的两个场景:": "实现方案的两个场景:", + "应用场景一:金丝雀环境和稳定环境有独立的域名进行隔离,实现全链路灰度。": "应用场景一:金丝雀环境和稳定环境有独立的域名进行隔离,实现全链路灰度。", + "应用场景二:使用相同域名,基于请求标签实现全链路灰度。": "应用场景二:使用相同域名,基于请求标签实现全链路灰度。", + "客户端染色": "", + "网关动态染色": "", + "网关静态染色": "", + "客户端染色流程指引": "", + "网关动态染色流程指引": "", + "网关静态染色流程指引": "", + "告警策略名称": "", + "启用状态": "", + "监控类型": "", + "更新时间": "", + "触发条件": "", + "持续": "持续", + "告警周期": "", + "每隔": "每隔", + "告警一次": "告警一次", + "告警主题": "", + "通知回调地址": "", + "策略ID/名称": "", + "告警规则": "", + "创建时间": "", + "编辑告警策略": "", + "新建告警策略": "", + "名字": "", + "当": "", + "持续时间": "", + "告警消息": "", + "请填写名称": "", + "请填写监控类型": "", + "请选择请求指标": "", + "请选择表达式": "", + "请选择阈值": "", + "请输入持续时长": "", + "请选择持续时长单位": "", + "请选择告警周期": "", + "请输入告警主题": "", + "请输入告警消息": "", + "业务监控": "", + "监控曲线": "", + "环比波动": "", + "环比上升": "", + "环比下降": "", + "天": "", + "服务发现连接数": "", + "配置获取连接数": "", + "客户端数": "", + "每1分钟告警一次": "", + "每5分钟告警一次": "", + "每15分钟告警一次": "", + "每1小时告警一次": "", + "每4小时告警一次": "", + "每天告警一次": "", + "名称": "", + "所有命名空间": "", + "所有服务": "", + "所有配置分组": "", + "权限": "", + "读|写": "", + "权限策略": "", + "可操作资源": "", + "License已超过最大过期时间": "", + "北极星服务治理中心": "北极星服务治理中心", + "一个支持多语言、多框架和异构基础设施的服务治理中心,提供服务发现、流量调度、熔断降级、限流鉴权和可观测性等服务治理功能。北极星治理中心默认提供服务注册功能,也可以搭配其他服务注册中心使用。": "一个支持多语言、多框架和异构基础设施的服务治理中心,提供服务发现、流量调度、熔断降级、限流鉴权和可观测性等服务治理功能。北极星治理中心默认提供服务注册功能,也可以搭配其他服务注册中心使用。", + "登录": "登录", + "外网访问建议设置访问控制策略": "外网访问建议设置访问控制策略", + "初始用户名和密码为": "初始用户名和密码为", + "用户名": "", + "密码": "", + "网络异常或用户名,密码错误": "", + "请输入用户名": "", + "请输入密码": "", + "选择用户": "", + "授权": "", + "预览": "", + "编辑策略": "", + "创建策略": "", + "备注": "", + "角色": "", + "请选择用户": "", + "请选择用户组": "", + "默认策略不可变更授权角色": "", + "资源": "", + "全部命名空间(含后续新增)": "", + "指定命名空间": "", + "全部服务(含后续新增)": "", + "指定服务": "", + "请选择服务": "", + "全部配置分组(含后续新增)": "", + "指定配置分组": "", + "请选择配置分组": "", + "读操作|写操作": "", + "策略名称": "", + "无选中用户": "", + "无选中用户组": "", + "完成": "", + "下一步": "", + "上一步": "", + "编辑成功": "", + "编辑失败": "", + "创建成功": "", + "创建失败": "", + "请输入名称": "", + "只能使用中文、数字、大小写字母 以及- _组成": "", + "最大长度为64": "", + "{{attr0}}({{attr1}})": "", + "(用户组)": "", + "(用户)": "", + "新建策略": "", + "默认策略(": "默认策略(", + "自定义策略(": "自定义策略(", + "无备注": "", + "用户|用户组": "", + "暂无对应授权对象": "", + "全部{{attr0}}(含后续新增)": "", + "暂无选中策略": "", + "确认删除如下策略?": "", + "删除后,策略不可用且无法恢复": "", + "删除成功": "", + "删除失败": "", + "用户详情({{attr0}})": "", + "用户信息": "", + "修改密码": "", + "账号名": "", + "账号ID": "", + "手机号": "", + "邮箱": "", + "生效中": "", + "已失效": "", + "重置": "", + "仅主账号可查看Token": "", + "修改成功": "", + "修改失败": "", + "{{attr0}}成功": "", + "{{attr0}}失败": "", + "重置成功": "", + "您已成功重置Token,请重新登录。": "", + "重置失败": "", + "(当前登录)": "", + "用户类型": "", + "主账号": "", + "子账号": "", + "用户id": "", + "查看Token": "", + "更多": "", + "关联用户组": "", + "确定": "确定", + "授权策略": "", + "请选择策略": "", + "未做改动": "", + "请输入6至17位的密码": "", + "编辑用户": "", + "新建用户": "", + "旧密码": "", + "如果您忘记了您的旧密码,可以联系您的主账号来重置密码": "", + "新密码": "", + "确认密码": "", + "修改密码成功": "", + "您已成功重置密码,请重新登录。": "", + "修改密码失败": "", + "请输入旧密码": "", + "请输入新密码": "", + "请确认密码": "", + "两次输入密码不一致": "", + "修改备注": "", + "请输入备注": "", + "授予权限的用户或者用户组,具有该命名空间的读写权限,所有用户具有读权限": "", + "支持按住shift进行多选": "", + "新建": "新建", + "编辑用户组": "", + "确认删除用户?": "", + "删除后,用户不可用且无法恢复": "", + "查看{{attr0}}的token": "", + "用户组详情({{attr0}})": "", + "用户组名": "", + "用户组ID": "", + "用户组名称": "", + "用户数量": "", + "新建用户组": "", + "关联成功": "", + "确认删除用户组?": "", + "删除后,用户组不可用且无法恢复": "", + "因为浏览器限制,此文件仅保存了部分内容": "", + "标签键": "", + "标签值": "", + "暂无标签": "", + "请输入完整键值对": "", + "编辑器正在加载中": { + "": "" + }, + "排序": "", + "标签名": "", + "key 最长不超过128个字符": "", + "value 最长不超过4096个字符": "", + "新增": "新增", + "近24小时": "", + "近3天": "", + "近7天": "", + "加载中": "", + "未找到指定资源,请检查资源是否存在": "", + "设置成功": "", + "请选择您想显示的列表详细信息。": "", + "根据您的分辨率,最多可勾选{{attr0}}个字段,已勾选{{attr1}}个。": "", + "自定义列表字段": "", + "请选择": "", + "加载失败": "", + "输入关键字搜索": "", + "暂无数据": "", + "找到{{attr0}}条结果": "", + "搜索\"{{attr0}}\"暂无数据": "", + "已选择 ({{attr0}})": "", + "提交失败": "", + "[deprecated] 建议使用对象递归,而不在返回值内递归": "", + "当前导出进度:{{attr0}}%": "", + "此浏览器版本过低,不支持导出功能": "", + "因文件过大,自动拆分为多个文件下载": "", + "导出成功": "", + "导出失败": "", + "请求错误": "", + "发布成功": "", + "发布失败": "", + "编辑待发布": "", + "历史发布": "历史发布", + "当前发布": "当前发布", + "编辑配置文件": "", + "新建配置文件": "", + "配置文件名": "", + "可通过/分隔符创建文件夹,强烈建议文件名带上后缀,如:datasource/master": { + "json": "" + }, + "文件格式: ": "", + "允许数字、英文字母、": { + "、-、_,限制128个字符": "" + }, + "长度不超过1024个字符": "", + "配置标签": "", + "该配置分组为只读配置分组": "", + "该命名空间为只读命名空间": "", + "请填写文件名": "", + "文件夹名字不可为空": "", + "请选择分组": "", + "请选择格式": "", + "应用模板": "应用模板", + "应用": "", + "模板": "", + "提供常用的配置文件模板,以方便进行快速配置": "", + "当前选择的模板与配置文件格式不符": "", + "模板格式": "", + "模板描述": "", + "模板预览": "", + "请确认应用模板": "", + "应用所选模板将会覆盖当前已编辑的内容": "", + "您当前选择的模板与配置文件格式不符,请检查后重试。": "", + "刷新成功": "", + "刷新配置": "刷新配置", + "提示": "", + "注意,刷新会导致丢失当前编辑内容": "注意,刷新会导致丢失当前编辑内容", + "请输入文件名搜索": "", + "查看发布历史": "查看发布历史", + "最后修改时间": "", + "最后发布时间": "", + "标签": "", + "最后修改人": "", + "最后发布人": "", + "格式": "", + "发布": "发布", + "保存": "保存", + "版本": "", + "发布时间": "", + "请选择发布记录": "请选择发布记录", + "未搜索到对应文件": "未搜索到对应文件", + "待发布": "待发布", + "确认删除配置文件?": "", + "删除后,无法恢复。": "", + "确认切换展示节点?": "", + "编辑未发布,现在切换将丢失已编辑内容": "", + "内容对比": "", + "保存成功": "", + "保存失败": "", + "配置文件": "", + "配置文件数": "", + "无权限": "", + "编辑配置文件组": "", + "新建配置文件组": "", + "分组名": "", + "高级配置": "高级配置", + "请填写分组名": "", + "请填写命名空间": "", + "确认删除配置组": "", + "删除配置组也会同时删除配置组下所有配置文件,请谨慎删除。": "", + "操作人": "", + "查看详情": "", + "分组": "", + "近1小时": "", + "近1天": "", + "近1周": "", + "新建监控图表": "", + "时间选择": "", + "指标名": "", + "筛选条件": "", + "条件": "", + "条件值": "", + "步长": "步长", + "主调方": "主调方", + "主调": "", + "汇总": "", + "被调方": "被调方", + "被调": "", + "查询": "查询", + "暂无图表数据": "", + "复制分享链接": "复制分享链接", + "保存当前配置": "保存当前配置", + "载入保存配置": "载入保存配置", + "筛选条件:": "筛选条件:", + "{{attr0}}\n :{{attr1}} ;": "", + "无": "", + "路由监控": "", + "熔断监控": "", + "限流监控": "", + "监控": "", + "本次筛选配置将会请求大量数据": "", + "请确认是否请求": "", + "已保存": "", + "客户端节点数": "", + "客户端连接数": "", + "总请求数": "", + "客户端访问北极星服务端请求数": "客户端访问北极星服务端请求数", + "请求时延": "", + "客户端访问北极星服务端请求时延": "客户端访问北极星服务端请求时延", + "服务数": "", + "实例数": "", + "配置分组数": "", + "配置数": "", + "概览": "", + "服务和配置统计": "", + "北极星服务端请求统计": "", + "1秒": "", + "1分": "", + "5分": "", + "1小时": "", + "全部命名空间汇总": "", + "时间范围": "", + "时间粒度": "", + "功能": "", + "全部功能汇总": "", + "全部接口汇总": "", + "无可选接口": "无可选接口", + "节点": "", + "全部节点汇总": "", + "无节点": "无节点", + "请求数": "", + "失败请求数": "", + "返回码分布": "", + "所有接口汇总-": "", + "所有节点汇总": "", + "{{attr0}}功能-{{attr1}}接口": "", + "所有接口汇总": "", + "{{attr0}}节点": "", + "全部汇总服务": "", + "无可选服务": "无可选服务", + "全部配置分组汇总": "", + "无配置分组": "无配置分组", + "总节点数": "", + "总连接数": "", + "注册中心连接数": "", + "配置中心连接数": "", + "成功请求数": "", + "请求成功率": "", + "均值": "", + "最大值": "", + "最小值": "", + "总服务数": "", + "在线服务数": "", + "异常服务数": "", + "离线服务数": "", + "总实例数": "", + "在线实例数": "", + "隔离实例数": "", + "异常实例数": "", + "配置分组总数": "", + "已发布配置文件数": "", + "总失败请求数": "", + "5xx失败请求数": "", + "4xx失败请求数": "", + "网络失败数": "", + "服务注册": "", + "服务发现": "", + "健康检查": "", + "配置读取": "", + "成功数": "", + "最大时延": "", + "平均时延": "", + "通过数": "", + "限流数": "", + "熔断数": "", + "半开数": "", + "被调服务名": "", + "被调接口名": "", + "被调实例分组": "", + "被调实例": "", + "被调请求标签": "", + "主调服务名": "", + "主调实例IP": "", + "主调请求标签": "", + "健康实例/总实例数": "", + "修改时间": "", + "编辑命名空间": "", + "新建命名空间": "", + "高级设置": "", + "请输入命名空间名称": "", + "确认删除命名空间": "", + "服务名": "", + "接口名": "", + "{{attr0}}({{attr1}}匹配)": "", + "该命名空间为只读的": "", + "无写权限": "", + "在该规则前新建规则": "", + "正则模式下,使用*代表选择所有": "", + "手动配置": "", + "JSON配置": "", + "以下服务": "", + "本服务调用以下服务或者接口时": "", + "调用本服务的以下接口时": "", + "如果满足以下任意条件,进行熔断": "如果满足以下任意条件,进行熔断", + "最大响应时间": "", + "半开时间": "", + "编辑方式": "", + "JSON编辑": "", + "请输入正确的JSON字符串": "", + "请输入命名空间": "", + "请输入服务名": "", + "编辑格式": "", + "规则类型": "", + "未更改": "", + "向服务器端提交变更": "", + "当以下服务调用本服务时,遵守下列熔断规则": "", + "当本服务调用以下服务时,遵守下列熔断规则": "", + "如果请求标签匹配,按以下策略熔断": "", + "熔断条件": "", + "当请求个数大于{{attr0}}个,且{{attr1}}大于{{attr2}}%时熔断": "", + "以超过{{attr0}}的请求作为超时请求,{{attr1}}大于{{attr2}}%时熔断": "", + "当连续请求错误超过{{attr0}}个时熔断": "", + "编辑规则": "", + "确认删除规则": "", + "连续错误率": "", + "精确": "", + "正则": "", + "被调规则": "", + "主调规则": "", + "仅用于恢复": "", + "用于熔断和恢复": "", + "部门": "", + "业务": "", + "版本号": "", + "服务标签({{attr0}}个)": "", + "就近访问": "", + "实例IP": "", + "健康状态": "", + "隔离状态": "", + "地区/地域/可用区": "", + "编辑服务实例": "", + "新建服务实例": "", + "隔离状态下,主调方无法发现隔离的服务实例,无论实例IP是否健康": "", + "多个IP以英文逗号、英文分号、空格或换行分隔,每次最多添加100个IP": "", + "多个端口以英文逗号、英文分号、空格或换行分隔,每次最多添加100个端口": "", + "实例标签可用于标识实例的用处、特征, 标签数量不能超过64": "", + "地域信息": "", + "请输入 Region": "", + "请输入 Zone": "", + "请输入 Campus": "", + "开启健康检查": "开启健康检查", + "如果开启,服务端负责检查服务实例的健康状态": "", + "健康检查方式": "", + "检查方式": "", + "请填写IP": "", + "请填写端口": "", + "请填写权重": "", + "请选择检查方式": "", + "请填写TTL": "", + "请选择实例": "", + "其他操作": "其他操作", + "复制IP": "复制IP", + "修改权重": "修改权重", + "修改健康状态": "修改健康状态", + "修改隔离状态": "修改隔离状态", + "实例ID": "", + "检查方式:": "检查方式:", + "; TTL:": "; TTL:", + "展示全部": "展示全部", + "确认删除实例": "", + "心跳上报": "", + "健康": "", + "异常": "", + "隔离": "", + "不隔离": "", + "请求标签": "", + "当以下服务调用本服务时": "", + "当本服务调用以下服务时": "", + "对带有以下标签的请求": "对带有以下标签的请求", + "按权重和优先级路由到以下实例分组": "按权重和优先级路由到以下实例分组", + "标签键不能为空": "", + "标签值不能为空": "", + "标签键不能一致": "", + "新建一条规则": "", + "当以下服务调用本服务时,遵守下列路由规则": "", + "当本服务调用以下服务时,遵守以下路由规则": "", + "如果请求标签匹配,按权重和优先级路由到以下实例分组": "", + "实例分组{{attr0}}": "", + "编辑路由规则": "", + "确认删除路由规则": "", + "图表编辑": "", + "服务信息": "", + "服务实例": "", + "路由规则": "", + "熔断规则": "", + "编辑服务": "", + "新建服务": "", + "开启就近访问": "", + "服务标签": "", + "服务标签可用于标识服务的用处、特征,格式为key:value": "", + "长度不超过1024个字符,标签数量不能超过64个": "", + "确认删除服务": "", + "标签展示": "", + "指向服务": "", + "别名所在命名空间": "", + "请选择指向服务": "", + "请选择别名所在命名空间": "", + "请填写别名": "", + "服务别名可以看作是服务的映射,访问服务别名等同于访问服务,允许多个服务别名指向同一个服务": "服务别名可以看作是服务的映射,访问服务别名等同于访问服务,允许多个服务别名指向同一个服务", + "新建别名": "", + "确认删除服务别名": "" +} diff --git a/web/src/app.tsx b/web/src/app.tsx index df00fbab..57f10d19 100644 --- a/web/src/app.tsx +++ b/web/src/app.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React, { useCallback } from 'react' import { Layout, NavMenu, Menu, List } from 'tea-component' import { Switch, Route, useHistory } from 'react-router-dom' @@ -182,7 +184,7 @@ export default function root() { target={'_blank'} rel='noreferrer' > - 文档 + 文档 - 账号信息 + 账号信息 { @@ -203,7 +205,7 @@ export default function root() { close() }} > - 退出 + 退出 )} diff --git a/web/src/buildConfig/Base.ts b/web/src/buildConfig/Base.ts index 06abf2b0..511199ef 100644 --- a/web/src/buildConfig/Base.ts +++ b/web/src/buildConfig/Base.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' export default class BuildConfig { get readonlyNamespace() { return [] diff --git a/web/src/buildConfig/index.ts b/web/src/buildConfig/index.ts index 584de44c..6a3e736b 100644 --- a/web/src/buildConfig/index.ts +++ b/web/src/buildConfig/index.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import Base from './Base' export const buildConfig = new Base() diff --git a/web/src/index.tsx b/web/src/index.tsx index 7342934d..54c35ff3 100644 --- a/web/src/index.tsx +++ b/web/src/index.tsx @@ -7,6 +7,11 @@ import { createHashHistory } from 'history' export const history = createHashHistory() import React from 'react' import ReactDOM from 'react-dom' +import i18n from 'i18next' +import { initReactI18next } from 'react-i18next' + +import LanguageDetector from 'i18next-browser-languagedetector' + import App from './app' import { Router, Switch, Route } from 'react-router-dom' import LoginPage from '@src/polaris/auth/login/Page' @@ -14,6 +19,19 @@ import LoginPageDuck from '@src/polaris/auth/login/PageDuck' import { connectWithDuck } from './polaris/common/helpers' const Login = connectWithDuck(LoginPage, LoginPageDuck as any) + +i18n + .use(LanguageDetector) + .use(initReactI18next) + .init({ + fallbackLng: 'en', + debug: true, + + interpolation: { + escapeValue: false, // not needed for react as it escapes by default + }, + }) + export default function render() { ReactDOM.unmountComponentAtNode(document.querySelector('#polaris-console')) ReactDOM.render( diff --git a/web/src/menu.ts b/web/src/menu.ts index edcc6461..bc4d35fa 100644 --- a/web/src/menu.ts +++ b/web/src/menu.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' export interface MenuItemConfig { id: string title: string @@ -7,29 +8,29 @@ export interface MenuItemConfig { export const MenuConfig: MenuItemConfig = { id: 'polaris', - title: '北极星服务治理', + title: t('北极星服务治理'), icon: null, subMenus: [ { id: 'namespace', - title: '命名空间', + title: t('命名空间'), icon: 'static/img/namespace.svg', subMenus: null, }, { id: 'serviceManage', - title: '注册中心', + title: t('注册中心'), icon: null, subMenus: [ { id: 'service', - title: '服务列表', + title: t('服务列表'), icon: 'static/img/service.svg', subMenus: null, }, { id: 'alias', - title: '服务别名', + title: t('服务别名'), icon: 'static/img/service.svg', subMenus: null, }, @@ -37,29 +38,29 @@ export const MenuConfig: MenuItemConfig = { }, { id: 'administration', - title: '服务网格', + title: t('服务网格'), icon: '', subMenus: [ { id: 'dynamic-route', - title: '动态路由', + title: t('动态路由'), icon: 'static/img/dynamic-route.svg', subMenus: [ { id: 'custom-route', - title: '自定义路由', + title: t('自定义路由'), icon: 'static/img/dynamic-route.svg', subMenus: null, }, { id: 'test-env-route', - title: '测试环境路由', + title: t('测试环境路由'), icon: 'static/img/dynamic-route.svg', subMenus: null, }, { id: 'gray-publish', - title: '灰度发布', + title: t('灰度发布'), icon: 'static/img/dynamic-route.svg', subMenus: null, }, @@ -67,13 +68,13 @@ export const MenuConfig: MenuItemConfig = { }, { id: 'circuitBreaker', - title: '熔断降级', + title: t('熔断降级'), icon: 'static/img/dynamic-route.svg', subMenus: null, }, { id: 'accesslimit', - title: '访问限流', + title: t('访问限流'), icon: 'static/img/dynamic-route.svg', subMenus: null, }, @@ -81,18 +82,18 @@ export const MenuConfig: MenuItemConfig = { }, { id: 'configuration', - title: '配置中心', + title: t('配置中心'), icon: null, subMenus: [ { id: 'filegroup', - title: '配置分组', + title: t('配置分组'), icon: 'static/img/route-monitor.svg', subMenus: null, }, { id: 'file-release-history', - title: '发布历史', + title: t('发布历史'), icon: 'static/img/route-monitor.svg', subMenus: null, }, @@ -100,18 +101,18 @@ export const MenuConfig: MenuItemConfig = { }, { id: 'observability', - title: '可观测性', + title: t('可观测性'), icon: null, subMenus: [ { id: 'registry-monitor', - title: '注册配置监控', + title: t('注册配置监控'), icon: 'static/img/circuit-monitor.svg', subMenus: null, }, { id: 'flow-monitor', - title: '流量监控', + title: t('流量监控'), icon: 'static/img/circuit-monitor.svg', subMenus: null, }, @@ -119,24 +120,24 @@ export const MenuConfig: MenuItemConfig = { }, { id: 'auth', - title: '权限控制', + title: t('权限控制'), icon: null, subMenus: [ { id: 'user', - title: '用户', + title: t('用户'), icon: 'static/img/user-icon.svg', subMenus: null, }, { id: 'usergroup', - title: '用户组', + title: t('用户组'), icon: 'static/img/user-icon.svg', subMenus: null, }, { id: 'policy', - title: '策略', + title: t('策略'), icon: 'static/img/user-icon.svg', subMenus: null, }, diff --git a/web/src/polaris/administration/accessLimiting/Page.tsx b/web/src/polaris/administration/accessLimiting/Page.tsx index d8c470ae..3ce614d3 100644 --- a/web/src/polaris/administration/accessLimiting/Page.tsx +++ b/web/src/polaris/administration/accessLimiting/Page.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { DuckCmpProps, purify } from 'saga-duck' import AccessLimitingDuck from './PageDuck' @@ -31,7 +33,7 @@ export default purify(function AccessLimitingPage(props: DuckCmpProps} @@ -41,13 +43,13 @@ export default purify(function AccessLimitingPage(props: DuckCmpProps - 新建限流规则 + 新建限流规则 } right={ <> handlers.changeName(value)} onClear={() => handlers.changeName('')} /> @@ -72,7 +74,7 @@ export default purify(function AccessLimitingPage(props: DuckCmpProps handlers.changeService(value), all: { value: '', - text: '全部', + text: t('全部'), }, options: filteredServiceList, }), @@ -96,7 +98,7 @@ export default purify(function AccessLimitingPage(props: DuckCmpProps handlers.changeStatus(value), all: { value: '', - text: '全部', + text: t('全部'), }, options: StatusOptions, }), diff --git a/web/src/polaris/administration/accessLimiting/PageDuck.tsx b/web/src/polaris/administration/accessLimiting/PageDuck.tsx index cfa6695f..0f8fd0c5 100644 --- a/web/src/polaris/administration/accessLimiting/PageDuck.tsx +++ b/web/src/polaris/administration/accessLimiting/PageDuck.tsx @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { createToPayload, reduceFromPayload } from 'saga-duck' import router from '@src/polaris/common/util/router' import { takeLatest } from 'redux-saga-catch' @@ -160,8 +161,10 @@ export default class AccessLimitingDuck extends GridPageDuck { watch: types.DELETE, fn: function*(item) { const confirm = yield Modal.confirm({ - message: `确认删除限流规则 ${item.name} 吗?`, - description: '删除后,无法恢复', + message: t('确认删除限流规则 {{attr0}} 吗?', { + attr0: item.name, + }), + description: t('删除后,无法恢复'), }) if (confirm) { yield deleteRateLimit([{ id: item.id }]) @@ -174,10 +177,13 @@ export default class AccessLimitingDuck extends GridPageDuck { type: OperationType.SINGLE, watch: types.SWITCH_STATUS, fn: function*(item: any) { - const ops = item.swtichStatusAction === SwitchStatusAction.disable ? '禁用' : '启用' + const ops = item.swtichStatusAction === SwitchStatusAction.disable ? t('禁用') : t('启用') const disable = item.swtichStatusAction === SwitchStatusAction.disable ? true : false const confirm = yield Modal.confirm({ - message: `确认${ops}限流规则 ${item.name} 吗?`, + message: t('确认{{attr0}}限流规则 {{attr1}} 吗?', { + attr0: ops, + attr1: item.name, + }), }) if (confirm) { yield enableRateLimit([{ id: item.id, disable }]) diff --git a/web/src/polaris/administration/accessLimiting/detail/Page.tsx b/web/src/polaris/administration/accessLimiting/detail/Page.tsx index e26299e6..9156b18e 100644 --- a/web/src/polaris/administration/accessLimiting/detail/Page.tsx +++ b/web/src/polaris/administration/accessLimiting/detail/Page.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { DuckCmpProps, purify } from 'saga-duck' import AccessLimitingDetailPageDuck from './PageDuck' @@ -21,13 +23,21 @@ insertCSS( ) export const MatchingLabelTips = ( <> - 多个请求匹配规则之间是且的关系 - 部分匹配运算符的说明如下: - 包含:多字符串取OR匹配,传入的值只要匹配到其中一个字符串,就算匹配成功。字符串之间使用逗号进行分割。值格式为'value1,value2,value3‘,匹配到其中一个就算成功。 + 多个请求匹配规则之间是且的关系 - 不包含:多字符串取反匹配,传入的值必须都没有出现在所配置的字符串列表中,才算匹配通过。值格式为'value1,value2,value3‘,全部不等于才算成功。 + 部分匹配运算符的说明如下: + + + + 包含:多字符串取OR匹配,传入的值只要匹配到其中一个字符串,就算匹配成功。字符串之间使用逗号进行分割。值格式为'value1,value2,value3‘,匹配到其中一个就算成功。 + + + + + 不包含:多字符串取反匹配,传入的值必须都没有出现在所配置的字符串列表中,才算匹配通过。值格式为'value1,value2,value3‘,全部不等于才算成功。 + ) @@ -66,32 +76,34 @@ export default purify(function AccessLimitingDetailPag(props: DuckCmpProps
- + {name || '-'} - + {LimitTypeMap[strLimitType]} - + - + {namespace} - + {service} - + {methodObj && methodObj['value']} {methodObj && LimitMethodTypeMap[methodObj['type']]} - + {argsList?.length > 0 && ( { const { type } = item return ( @@ -158,13 +170,17 @@ export default purify(function AccessLimitingDetailPag(props: DuckCmpProps - +
-
限流条件
- 满足以下任意条件即可触发限流 +
+ 限流条件 +
+ + 满足以下任意条件即可触发限流 +
- + {amounts?.length > 0 && (
{ const { validDurationNum, validDurationUnit } = item return ( @@ -185,10 +201,15 @@ export default purify(function AccessLimitingDetailPag(props: DuckCmpProps { const { maxAmount } = item - return {maxAmount}次 + return ( + + {maxAmount} + + + ) }, }, ]} @@ -198,39 +219,48 @@ export default purify(function AccessLimitingDetailPag(props: DuckCmpProps - {regex_combine ? '是' : '否'} + {regex_combine ? t('是') : t('否')}
-
限流方案
- 满足限流触发条件后的处理方案 +
+ 限流方案 +
+ + 满足限流触发条件后的处理方案 +
- + {LimitActionMap[action]} {strLimitType === LimitType.GLOBAL && ( {LimitFailoverMap[failover]} )} {action === LimitAction.UNIRATE && ( - - {max_queue_delay}秒 + + + {max_queue_delay} + + )} - - {disable ? '是' : '否'} + + {disable ? t('是') : t('否')} diff --git a/web/src/polaris/administration/accessLimiting/getColumns.tsx b/web/src/polaris/administration/accessLimiting/getColumns.tsx index 5f7a6a06..a284f647 100644 --- a/web/src/polaris/administration/accessLimiting/getColumns.tsx +++ b/web/src/polaris/administration/accessLimiting/getColumns.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import * as React from 'react' import AccessLimitingDuck from './PageDuck' import { Text, Copy } from 'tea-component' @@ -11,7 +13,7 @@ import { Link } from 'react-router-dom' export default ({ creators }: AccessLimitingDuck): Column[] => [ { key: 'idName', - header: 'ID/规则名', + header: t('ID/规则名'), width: 280, render: x => ( <> @@ -26,27 +28,36 @@ export default ({ creators }: AccessLimitingDuck): Column[] => [ }, { key: 'disable', - header: '状态', - render: x => (x.disable ? 已启用 : 未启用), + header: t('状态'), + render: x => + x.disable ? ( + + 已启用 + + ) : ( + + 未启用 + + ), }, { key: 'namespace', - header: '命名空间', + header: t('命名空间'), render: x => {x.namespace || '-'}, }, { key: 'service', - header: '服务名称', + header: t('服务名称'), render: x => {x.service || '-'}, }, { key: 'method', - header: '接口名称', + header: t('接口名称'), render: x => {x.method.value || '-'}, }, { key: 'ctimeMtime', - header: '创建时间/修改时间', + header: t('创建时间/修改时间'), render: x => ( <> @@ -59,7 +70,7 @@ export default ({ creators }: AccessLimitingDuck): Column[] => [ }, { key: 'etime', - header: '启用时间', + header: t('启用时间'), render: x => ( <> {x.etime || '-'} @@ -68,7 +79,7 @@ export default ({ creators }: AccessLimitingDuck): Column[] => [ }, { key: 'action', - header: '操作', + header: t('操作'), render: x => { const actions: { id: string @@ -77,7 +88,7 @@ export default ({ creators }: AccessLimitingDuck): Column[] => [ }[] = [ { id: 'switchStatus', - text: x.disable ? '禁用' : '启用', + text: x.disable ? t('禁用') : t('启用'), fn: dispatch => { const swtichStatusAction = x.disable ? SwitchStatusAction.disable : SwitchStatusAction.start dispatch(creators.switchStatus(x.id, x.name, swtichStatusAction)) @@ -85,14 +96,14 @@ export default ({ creators }: AccessLimitingDuck): Column[] => [ }, { id: 'modify', - text: '编辑', + text: t('编辑'), fn: dispatch => { dispatch(creators.modify(x)) }, }, { id: 'remove', - text: '删除', + text: t('删除'), fn: dispatch => { dispatch(creators.delete(x)) }, diff --git a/web/src/polaris/administration/accessLimiting/operations/Create.tsx b/web/src/polaris/administration/accessLimiting/operations/Create.tsx index 12a593e4..4c3f5634 100644 --- a/web/src/polaris/administration/accessLimiting/operations/Create.tsx +++ b/web/src/polaris/administration/accessLimiting/operations/Create.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { DuckCmpProps, purify } from 'saga-duck' import LimitRuleCreatePageDuck from './CreateDuck' @@ -54,13 +56,21 @@ insertCSS( ) export const MatchingLabelTips = ( <> - 多个请求匹配规则之间是且的关系 - 部分匹配运算符的说明如下: - 包含:多字符串取OR匹配,传入的值只要匹配到其中一个字符串,就算匹配成功。字符串之间使用逗号进行分割。值格式为'value1,value2,value3‘,匹配到其中一个就算成功。 + 多个请求匹配规则之间是且的关系 - 不包含:多字符串取反匹配,传入的值必须都没有出现在所配置的字符串列表中,才算匹配通过。值格式为'value1,value2,value3‘,全部不等于才算成功。 + 部分匹配运算符的说明如下: + + + + 包含:多字符串取OR匹配,传入的值只要匹配到其中一个字符串,就算匹配成功。字符串之间使用逗号进行分割。值格式为'value1,value2,value3‘,匹配到其中一个就算成功。 + + + + + 不包含:多字符串取反匹配,传入的值必须都没有出现在所配置的字符串列表中,才算匹配通过。值格式为'value1,value2,value3‘,全部不等于才算成功。 + ) @@ -128,7 +138,7 @@ export default purify(function LimitRuleCreatePage(props: DuckCmpProps ) @@ -139,7 +149,7 @@ export default purify(function LimitRuleCreatePage(props: DuckCmpProps } else { - keyComponent = keyField.setValue(key)} /> + keyComponent = keyField.setValue(key)} /> } return ( @@ -179,13 +189,13 @@ export default purify(function LimitRuleCreatePage(props: DuckCmpProps ) } else { valueComponent = ( - valueField.setValue(value)} /> + valueField.setValue(value)} /> ) } @@ -223,16 +233,16 @@ export default purify(function LimitRuleCreatePage(props: DuckCmpProps
- + - + - + - +
{ const { type, key } = item.getFields(['type', 'key']) const validate = type.getTouched() && type.getError() @@ -431,11 +443,11 @@ export default purify(function LimitRuleCreatePage(props: DuckCmpProps - 添加 + 添加 {argumentsList?.length > 0 && ( )} @@ -445,13 +457,17 @@ export default purify(function LimitRuleCreatePage(props: DuckCmpProps - +
-
限流条件
- 满足以下任意条件即可触发限流 +
+ 限流条件 +
+ + 满足以下任意条件即可触发限流 +
- + {amountsList?.length > 0 && (
{ @@ -463,7 +479,7 @@ export default purify(function LimitRuleCreatePage(props: DuckCmpProps { const { validDurationNum, validDurationUnit } = item.getFields([ 'validDurationNum', @@ -495,11 +511,11 @@ export default purify(function LimitRuleCreatePage(props: DuckCmpProps { const { maxAmount } = item.getFields(['maxAmount']) return ( - + - 添加 + 添加 {amountsList?.length > 0 && ( )}
-
限流方案
- 满足限流触发条件后的处理方案 +
+ 限流方案 +
+ + 满足限流触发条件后的处理方案 +
- + {limitType === LimitType.GLOBAL && ( )} {actionField.getValue() === LimitAction.UNIRATE && ( - - + + @@ -604,13 +626,13 @@ export default purify(function LimitRuleCreatePage(props: DuckCmpProps - + diff --git a/web/src/polaris/administration/accessLimiting/operations/CreateDuck.ts b/web/src/polaris/administration/accessLimiting/operations/CreateDuck.ts index ee3cc3cd..84b6e4e8 100644 --- a/web/src/polaris/administration/accessLimiting/operations/CreateDuck.ts +++ b/web/src/polaris/administration/accessLimiting/operations/CreateDuck.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { createToPayload, reduceFromPayload } from 'saga-duck' import DetailPage from '@src/polaris/common/ducks/DetailPage' import Form from '@src/polaris/common/ducks/Form' @@ -41,43 +42,43 @@ export interface Values extends CreateLimitRulesBaseParams { const validator = Form.combineValidators({ name(v) { if (!v) { - return '请填写限流规则名称' + return t('请填写限流规则名称') } }, namespace(v) { if (!v) { - return '请选择命名空间' + return t('请选择命名空间') } }, service(v) { if (!v) { - return '请选择服务名' + return t('请选择服务名') } }, arguments: [ { type(v) { if (!v) { - return '请选择类型' + return t('请选择类型') } }, value(v, data) { if (!v && data.type === LimitArgumentsType.CALLER_SERVICE) { - return '请选择服务名' + return t('请选择服务名') } if (!v && data.type === LimitArgumentsType.CALLER_IP) { - return '请输入IP' + return t('请输入IP') } if (!v && data.type !== LimitArgumentsType.CALLER_IP) { - return '请输入value值' + return t('请输入value值') } }, key(v, data) { if (!v && data.type === LimitArgumentsType.CALLER_SERVICE) { - return '请选择命名空间' + return t('请选择命名空间') } if (!v) { - return '请输入key值' + return t('请输入key值') } }, }, diff --git a/web/src/polaris/administration/accessLimiting/types.ts b/web/src/polaris/administration/accessLimiting/types.ts index 3e245109..96bbb78d 100644 --- a/web/src/polaris/administration/accessLimiting/types.ts +++ b/web/src/polaris/administration/accessLimiting/types.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { Values } from './operations/CreateDuck' export interface Lists { @@ -13,11 +14,11 @@ export enum LimitType { export const LimitTypeOptions = [ { value: LimitType.LOCAL, - text: '单机限流', + text: t('单机限流'), }, { value: LimitType.GLOBAL, - text: '分布式限流', + text: t('分布式限流'), }, ] @@ -34,11 +35,11 @@ export enum LimitAction { export const LimitActionOptions = [ { value: LimitAction.REJECT, - text: '快速失败', + text: t('快速失败'), }, { value: LimitAction.UNIRATE, - text: '匀速排队', + text: t('匀速排队'), }, ] @@ -61,11 +62,11 @@ export enum SwitchStatusAction { export const StatusOptions = [ { value: RuleStatus.enabled, - text: '已启用', + text: t('已启用'), }, { value: RuleStatus.notEnabled, - text: '未启用', + text: t('未启用'), }, ] @@ -80,23 +81,23 @@ export enum LimitMethodType { export const LimitMethodTypeOptions = [ { value: LimitMethodType.EXACT, - text: '全匹配', + text: t('全匹配'), }, { value: LimitMethodType.REGEX, - text: '正则表达式', + text: t('正则表达式'), }, { value: LimitMethodType.NOT_EQUALS, - text: '不等于', + text: t('不等于'), }, { value: LimitMethodType.IN, - text: '包含', + text: t('包含'), }, { value: LimitMethodType.NOT_IN, - text: '不包含', + text: t('不包含'), }, ] @@ -117,27 +118,27 @@ export enum LimitArgumentsType { export const LimitArgumentsTypeOptions = [ { value: LimitArgumentsType.CUSTOM, - text: '自定义', + text: t('自定义'), }, { value: LimitArgumentsType.HEADER, - text: '请求头(HEADER)', + text: t('请求头(HEADER)'), }, { value: LimitArgumentsType.QUERY, - text: '请求参数(QUERY)', + text: t('请求参数(QUERY)'), }, { value: LimitArgumentsType.METHOD, - text: '方法(METHOD)', + text: t('方法(METHOD)'), }, { value: LimitArgumentsType.CALLER_SERVICE, - text: '主调服务', + text: t('主调服务'), }, { value: LimitArgumentsType.CALLER_IP, - text: '主调IP', + text: t('主调IP'), }, ] @@ -154,11 +155,11 @@ export enum LimitFailover { export const LimitFailoverOptions = [ { value: LimitFailover.FAILOVER_LOCAL, - text: '退化至单机限流', + text: t('退化至单机限流'), }, { value: LimitFailover.FAILOVER_PASS, - text: '直接通过', + text: t('直接通过'), }, ] @@ -177,15 +178,15 @@ export enum LimitAmountsValidationUnit { export const LimitAmountsValidationUnitOptions = [ { value: LimitAmountsValidationUnit.s, - text: '秒', + text: t('秒'), }, { value: LimitAmountsValidationUnit.m, - text: '分钟', + text: t('分钟'), }, { value: LimitAmountsValidationUnit.h, - text: '小时', + text: t('小时'), }, ] diff --git a/web/src/polaris/administration/breaker/Page.tsx b/web/src/polaris/administration/breaker/Page.tsx index 56ad54d8..ea17d11d 100644 --- a/web/src/polaris/administration/breaker/Page.tsx +++ b/web/src/polaris/administration/breaker/Page.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { DuckCmpProps, purify } from 'saga-duck' import CircuitBreakerDuck from './PageDuck' @@ -46,22 +48,22 @@ export enum TagSearchType { } const EnableOptions = [ { - text: '已启用', + text: t('已启用'), value: 'true', - name: '已启用', + name: t('已启用'), key: 'true', }, { - text: '未启用', + text: t('未启用'), value: 'false', - name: '未启用', + name: t('未启用'), key: 'false', }, ] export const DefaultBreakerTag = { type: 'input', key: TagSearchType.Name, - name: '规则名', + name: t('规则名'), } function getTagAttributes(props: DuckCmpProps) { const { duck, store } = props @@ -71,34 +73,34 @@ function getTagAttributes(props: DuckCmpProps) { { type: 'single', key: TagSearchType.SourceNamespace, - name: '源命名空间', + name: t('源命名空间'), values: namespaceList, }, { type: 'input', key: TagSearchType.SourceService, - name: '源服务', + name: t('源服务'), }, { type: 'single', key: TagSearchType.DestNamespace, - name: '目标命名空间', + name: t('目标命名空间'), values: namespaceList, }, { type: 'input', key: TagSearchType.DestService, - name: '目标服务', + name: t('目标服务'), }, { type: 'input', key: TagSearchType.DestMethod, - name: '目标方法', + name: t('目标方法'), }, { type: 'input', key: TagSearchType.Description, - name: '描述', + name: t('描述'), }, ] } @@ -133,7 +135,7 @@ export default purify(function CircuitBreakerPage(props: DuckCmpProps - 新建熔断规则 + 新建熔断规则 } right={ @@ -146,7 +148,7 @@ export default purify(function CircuitBreakerPage(props: DuckCmpProps handlers.changeTags(value)} - tips={'请选择条件进行过滤'} + tips={t('请选择条件进行过滤')} hideHelp={true} /> @@ -168,14 +170,14 @@ export default purify(function CircuitBreakerPage(props: DuckCmpProps - + {ruleDetail.description || '-'} - + {ruleDetail.errorConditions?.map(item => { return ( @@ -199,7 +201,7 @@ export default purify(function CircuitBreakerPage(props: DuckCmpProps {ErrorConditionMap[item.inputType]} {item.inputType === ErrorConditionType.DELAY - ? '超过' + ? t('超过') : LimitMethodTypeMap[item.condition?.type]} {item.inputType === ErrorConditionType.DELAY ? `${item.condition?.value}ms` @@ -210,7 +212,7 @@ export default purify(function CircuitBreakerPage(props: DuckCmpProps - + {ruleDetail.triggerCondition?.map(item => { return ( @@ -220,14 +222,19 @@ export default purify(function CircuitBreakerPage(props: DuckCmpProps {TriggerTypeMap[item.triggerType].text} {'>='} - {item.errorPercent}% (统计周期:{item.interval},最小请求数:{item.minimumRequest}) + {item.errorPercent} + % (统计周期: + {item.interval} + ,最小请求数: + {item.minimumRequest}) )} {item.triggerType === TriggerType.CONSECUTIVE_ERROR && ( <> {TriggerTypeMap[item.triggerType].text} {'>='} - {item.errorCount}个 + {item.errorCount} + )} @@ -236,19 +243,27 @@ export default purify(function CircuitBreakerPage(props: DuckCmpProps - + {BreakLevelMap[ruleDetail.level]} - - {`${ruleDetail.recoverCondition.sleepWindow}秒` || '-'} + + + {t('{{attr0}}秒', { + attr0: ruleDetail.recoverCondition.sleepWindow, + }) || '-'} + - - 当满足{ruleDetail.recoverCondition.consecutiveSuccess}个连续成功请求后恢复 + + + 当满足 + {ruleDetail.recoverCondition.consecutiveSuccess} + 个连续成功请求后恢复 + - - {ruleDetail.faultDetectConfig.enable ? '开启' : '关闭' || '-'} + + {ruleDetail.faultDetectConfig.enable ? t('开启') : t('关闭') || '-'} - + {ruleDetail.fallbackConfig.enable ? (
{ return ( <> @@ -278,12 +293,12 @@ export default purify(function CircuitBreakerPage(props: DuckCmpProps
) : ( - '未开启' + t('未开启') )}
@@ -301,7 +316,7 @@ export default purify(function CircuitBreakerPage(props: DuckCmpProps} diff --git a/web/src/polaris/administration/breaker/PageDuck.tsx b/web/src/polaris/administration/breaker/PageDuck.tsx index d70f53ff..133b9e2b 100644 --- a/web/src/polaris/administration/breaker/PageDuck.tsx +++ b/web/src/polaris/administration/breaker/PageDuck.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import { createToPayload, reduceFromPayload } from 'saga-duck' import GridPageDuck, { Filter as BaseFilter } from '../../common/ducks/GridPage' import { takeLatest } from 'redux-saga-catch' @@ -213,8 +215,10 @@ export default class ServicePageDuck extends GridPageDuck { yield takeLatest(types.REMOVE, function*(action) { const rule = action.payload const confirm = yield Modal.confirm({ - message: `确认删除规则 ${rule.name} 吗?`, - description: '删除后,无法恢复', + message: t('确认删除规则 {{attr0}} 吗?', { + attr0: rule.name, + }), + description: t('删除后,无法恢复'), }) if (confirm) { yield deleteCircuitBreaker([{ id: rule.id }]) @@ -227,9 +231,12 @@ export default class ServicePageDuck extends GridPageDuck { }) yield takeLatest(types.TOGGLE_RULE, function*(action) { const rule = action.payload - const ops = rule.enable ? '禁用' : '启用' + const ops = rule.enable ? t('禁用') : t('启用') const confirm = yield Modal.confirm({ - message: `确认${ops}规则 ${rule.name} 吗?`, + message: t('确认{{attr0}}规则 {{attr1}} 吗?', { + attr0: ops, + attr1: rule.name, + }), }) if (confirm) { yield enableCircuitBreaker([{ id: rule.id, enable: !rule.enable }]) diff --git a/web/src/polaris/administration/breaker/faultDetect/Page.tsx b/web/src/polaris/administration/breaker/faultDetect/Page.tsx index 63970894..64ebd18f 100644 --- a/web/src/polaris/administration/breaker/faultDetect/Page.tsx +++ b/web/src/polaris/administration/breaker/faultDetect/Page.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { DuckCmpProps, purify } from 'saga-duck' import FaultDetectDuck from './PageDuck' @@ -19,7 +21,7 @@ export enum TagSearchType { export const DefaultBreakerTag = { type: 'input', key: TagSearchType.Name, - name: '规则名', + name: t('规则名'), } function getTagAttributes(props: DuckCmpProps) { const { duck, store } = props @@ -29,23 +31,23 @@ function getTagAttributes(props: DuckCmpProps) { { type: 'single', key: TagSearchType.DestNamespace, - name: '目标命名空间', + name: t('目标命名空间'), values: namespaceList, }, { type: 'input', key: TagSearchType.DestService, - name: '目标服务', + name: t('目标服务'), }, { type: 'input', key: TagSearchType.DestMethod, - name: '目标方法', + name: t('目标方法'), }, { type: 'input', key: TagSearchType.Description, - name: '描述', + name: t('描述'), }, ] } @@ -57,8 +59,8 @@ export default purify(function FaultDetectPage(props: DuckCmpProps ({ - changeTags: (tags) => dispatch(creators.changeTags(tags)), - setExpandedKeys: (v) => dispatch(creators.setExpandedKeys(v)), + changeTags: tags => dispatch(creators.changeTags(tags)), + setExpandedKeys: v => dispatch(creators.setExpandedKeys(v)), }), [], ) @@ -78,7 +80,7 @@ export default purify(function FaultDetectPage(props: DuckCmpProps - 新建主动探测规则 + 新建主动探测规则 } right={ @@ -90,8 +92,8 @@ export default purify(function FaultDetectPage(props: DuckCmpProps handlers.changeTags(value)} - tips={'请选择条件进行过滤'} + onChange={value => handlers.changeTags(value)} + tips={t('请选择条件进行过滤')} hideHelp={true} /> @@ -109,21 +111,24 @@ export default purify(function FaultDetectPage(props: DuckCmpProps handlers.setExpandedKeys(keys), - render: (record) => { + onExpandedKeysChange: keys => handlers.setExpandedKeys(keys), + render: record => { const ruleDetail = ruleInfoMap[record.id] as FaultDetectRule return ruleDetail ? (
- + {ruleDetail.description || '-'} - - {ruleDetail.interval || '-'}秒 + + + {ruleDetail.interval || '-'} + + - + {ruleDetail.port || '-'} - + {ruleDetail.protocol || '-'} {ruleDetail.protocol === FaultDetectProtocol.HTTP && ( @@ -136,7 +141,7 @@ export default purify(function FaultDetectPage(props: DuckCmpProps - {ruleDetail.httpConfig.headers.map((item) => { + {ruleDetail.httpConfig.headers.map(item => { return ( {item.key}:{item.value} diff --git a/web/src/polaris/administration/breaker/faultDetect/PageDuck.tsx b/web/src/polaris/administration/breaker/faultDetect/PageDuck.tsx index 562b814f..b9d8e970 100644 --- a/web/src/polaris/administration/breaker/faultDetect/PageDuck.tsx +++ b/web/src/polaris/administration/breaker/faultDetect/PageDuck.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import { createToPayload, reduceFromPayload } from 'saga-duck' import GridPageDuck, { Filter as BaseFilter } from '../../../common/ducks/GridPage' import { takeLatest } from 'redux-saga-catch' @@ -127,7 +129,7 @@ export default class FaultDetectDuck extends GridPageDuck { } *loadInfo() { const namespaceList = yield describeNamespaces() - const options = namespaceList.map((item) => ({ + const options = namespaceList.map(item => ({ ...item, text: item.name, value: item.name, @@ -143,22 +145,22 @@ export default class FaultDetectDuck extends GridPageDuck { const { types, selector, creators } = this yield* super.saga() yield* this.loadInfo() - yield takeLatest(types.CHANGE_TAGS, function* (action) { + yield takeLatest(types.CHANGE_TAGS, function*(action) { const tags = action.payload const customFilters = { ...EmptyCustomFilter } - const validTags = tags.map((item) => { + const validTags = tags.map(item => { if (item.attr) return item else return { ...item, attr: DefaultBreakerTag } }) yield put({ type: types.SET_TAGS, payload: validTags }) - validTags.forEach((tag) => { + validTags.forEach(tag => { const key = tag?.attr?.key || TagSearchType.Name if (tag.attr.type === 'input') customFilters[key] = tag.values[0].name else customFilters[key] = tag.values[0].key || tag.values[0].value }) yield put({ type: types.SET_CUSTOM_FILTERS, payload: customFilters }) }) - yield takeLatest(types.SET_EXPANDED_KEY, function* (action) { + yield takeLatest(types.SET_EXPANDED_KEY, function*(action) { const { ruleInfoMap } = selector(yield select()) const expandedKeys = action.payload const obj = { ...ruleInfoMap } @@ -170,11 +172,13 @@ export default class FaultDetectDuck extends GridPageDuck { } } }) - yield takeLatest(types.REMOVE, function* (action) { + yield takeLatest(types.REMOVE, function*(action) { const rule = action.payload const confirm = yield Modal.confirm({ - message: `确认删除规则 ${rule.name} 吗?`, - description: '删除后,无法恢复', + message: t('确认删除规则 {{attr0}} 吗?', { + attr0: rule.name, + }), + description: t('删除后,无法恢复'), }) if (confirm) { yield deleteFaultDetect([{ id: rule.id }]) diff --git a/web/src/polaris/administration/breaker/faultDetect/getColumns.tsx b/web/src/polaris/administration/breaker/faultDetect/getColumns.tsx index ae96a3d2..418e9725 100644 --- a/web/src/polaris/administration/breaker/faultDetect/getColumns.tsx +++ b/web/src/polaris/administration/breaker/faultDetect/getColumns.tsx @@ -1,3 +1,4 @@ +import { t } from 'i18next' import * as React from 'react' import FaultDetectDuck from './PageDuck' import { Text, Copy } from 'tea-component' @@ -15,7 +16,7 @@ export default (props: DuckCmpProps): Column[] return [ { key: 'idName', - header: 'ID/规则名', + header: t('ID/规则名'), width: 280, render: x => { return ( @@ -32,7 +33,7 @@ export default (props: DuckCmpProps): Column[] }, { key: 'namespace', - header: '命名空间', + header: t('命名空间'), render: x => { return ( <> @@ -43,7 +44,7 @@ export default (props: DuckCmpProps): Column[] }, { key: 'service', - header: '服务', + header: t('服务'), render: x => { return ( <> @@ -54,7 +55,7 @@ export default (props: DuckCmpProps): Column[] }, { key: 'method', - header: '接口', + header: t('接口'), render: x => { return ( <> @@ -65,7 +66,7 @@ export default (props: DuckCmpProps): Column[] }, { key: 'ctimemtime', - header: '创建时间/修改时间', + header: t('创建时间/修改时间'), render: x => { return ( <> @@ -77,18 +78,18 @@ export default (props: DuckCmpProps): Column[] }, { key: 'action', - header: '操作', + header: t('操作'), render: x => { return ( { router.navigate(`/faultDetect-create?id=${x.id}`) }} /> { dispatch(creators.remove(x)) }} diff --git a/web/src/polaris/administration/breaker/faultDetect/model.ts b/web/src/polaris/administration/breaker/faultDetect/model.ts index 4825079f..f54f6f5c 100644 --- a/web/src/polaris/administration/breaker/faultDetect/model.ts +++ b/web/src/polaris/administration/breaker/faultDetect/model.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { apiRequest, getApiRequest, putApiRequest } from '@src/polaris/common/util/apiRequest' import { FaultDetectRule } from './types' diff --git a/web/src/polaris/administration/breaker/faultDetect/operations/Create.tsx b/web/src/polaris/administration/breaker/faultDetect/operations/Create.tsx index ab7504c4..e38a4941 100644 --- a/web/src/polaris/administration/breaker/faultDetect/operations/Create.tsx +++ b/web/src/polaris/administration/breaker/faultDetect/operations/Create.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { DuckCmpProps, purify } from 'saga-duck' import DetailPage from '@src/polaris/common/duckComponents/DetailPage' @@ -96,22 +98,22 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) store={store} duck={duck} dispatch={dispatch} - title={composedId?.id ? '编辑主动探测规则' : '新建主动探测规则'} + title={composedId?.id ? t('编辑主动探测规则') : t('新建主动探测规则')} backRoute={backRoute} > - + - + - + { if (value === '*') { destinationNamespace.setValue('*') @@ -125,19 +127,21 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) type={'simulate'} appearance={'button'} matchButtonWidth - placeholder='请选择命名空间' + placeholder={t('请选择命名空间')} size='m' /> - + ) }) || []), ]), ]} - tips='没有匹配的服务名称' + tips={t('没有匹配的服务名称')} onChange={value => { destinationService.setValue(value) }} @@ -155,7 +159,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) {ref => ( { destinationService.setValue(value) }} @@ -164,8 +168,12 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) )} - - + + ) matchButtonWidth /> - + { @@ -185,7 +193,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) hideButton /> - + { @@ -196,7 +204,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) min={0} /> - + { @@ -211,8 +219,8 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) ) {protocol.getValue() === FaultDetectProtocol.HTTP && ( <> - + ) /> - + {[...headers.asArray()].map((item, index) => { const { key, value } = item.getFields(['key', 'value']) return ( - - + + {headers.getValue().length > 1 && ( - ) @@ -342,7 +354,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) diff --git a/web/src/polaris/administration/breaker/faultDetect/operations/CreateDuck.ts b/web/src/polaris/administration/breaker/faultDetect/operations/CreateDuck.ts index def6b47e..6a095b35 100644 --- a/web/src/polaris/administration/breaker/faultDetect/operations/CreateDuck.ts +++ b/web/src/polaris/administration/breaker/faultDetect/operations/CreateDuck.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { createToPayload, reduceFromPayload } from 'saga-duck' import DetailPage from '@src/polaris/common/ducks/DetailPage' import Form from '@src/polaris/common/ducks/Form' @@ -187,45 +188,45 @@ export default class CircuitBreakerCreatePageDuck extends DetailPage { const validator = Form.combineValidators({ name(v) { if (!v) { - return '请填写规则名称' + return t('请填写规则名称') } if (!/^[a-zA-Z0-9-_]([a-zA-Z0-9-_]{1,64})?$/.test(v)) { - return '名称只能含有数字,字母,下划线及中划线' + return t('名称只能含有数字,字母,下划线及中划线') } }, targetService: { namespace(v) { if (!v) { - return '请选择命名空间' + return t('请选择命名空间') } }, service(v) { if (!v) { - return '请选择服务名' + return t('请选择服务名') } }, }, timeout(v) { - if (!v) return '请输入超时时间' + if (!v) return t('请输入超时时间') }, httpConfig(v, values) { if (values.protocol !== FaultDetectProtocol.HTTP) return const res = Form.combineValidators({ url(v) { if (!v) { - return '请输入url' + return t('请输入url') } }, headers: [ { key(v) { if (!v) { - return '请输入键' + return t('请输入键') } }, value(v) { if (!v) { - return '请输入值' + return t('请输入值') } }, }, @@ -238,7 +239,7 @@ const validator = Form.combineValidators({ return Form.combineValidators({ send(v) { if (!v) { - return '请输入值' + return t('请输入值') } }, })(v, values.tcpConfig) @@ -248,7 +249,7 @@ const validator = Form.combineValidators({ return Form.combineValidators({ send(v) { if (!v) { - return '请输入值' + return t('请输入值') } }, })(v, values.udpConfig) diff --git a/web/src/polaris/administration/breaker/faultDetect/types.ts b/web/src/polaris/administration/breaker/faultDetect/types.ts index ea48f1fa..a8b2c642 100644 --- a/web/src/polaris/administration/breaker/faultDetect/types.ts +++ b/web/src/polaris/administration/breaker/faultDetect/types.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { KeyValuePair } from '@src/polaris/configuration/fileGroup/types' export interface FaultDetectRule { @@ -39,7 +40,7 @@ export enum FaultDetectProtocol { TCP = 'TCP', UDP = 'UDP', } -export const FaultDetectProtocolOptions = Object.keys(FaultDetectProtocol).map((item) => ({ text: item, value: item })) +export const FaultDetectProtocolOptions = Object.keys(FaultDetectProtocol).map(item => ({ text: item, value: item })) export enum FaultDetectHttpMethod { GET = 'GET', POST = 'POST', @@ -51,7 +52,7 @@ export enum FaultDetectHttpMethod { CONNECT = 'CONNECT', TRACE = 'TRACE', } -export const FaultDetectHttpMethodOptions = Object.keys(FaultDetectHttpMethod).map((item) => ({ +export const FaultDetectHttpMethodOptions = Object.keys(FaultDetectHttpMethod).map(item => ({ text: item, value: item, })) diff --git a/web/src/polaris/administration/breaker/getColumns.tsx b/web/src/polaris/administration/breaker/getColumns.tsx index b3c38d78..9cf62138 100644 --- a/web/src/polaris/administration/breaker/getColumns.tsx +++ b/web/src/polaris/administration/breaker/getColumns.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import * as React from 'react' import CircuitBreakerDuck from './PageDuck' import { Text, Copy } from 'tea-component' @@ -16,7 +18,7 @@ export default (props: DuckCmpProps): Column { return ( @@ -33,32 +35,54 @@ export default (props: DuckCmpProps): Column (x.enable ? 已启用 : 未启用), + header: t('状态'), + render: x => + x.enable ? ( + + 已启用 + + ) : ( + + 未启用 + + ), }, { key: 'source', - header: '主调服务', + header: t('主调服务'), render: x => { return ( <> - 命名空间: {x.ruleMatcher?.source?.namespace} - 服务: {x.ruleMatcher?.source?.service} + + 命名空间: + {x.ruleMatcher?.source?.namespace} + + + 服务: + {x.ruleMatcher?.source?.service} + ) }, }, { key: 'destination', - header: '被调服务', + header: t('被调服务'), render: x => { return ( <> - 命名空间: {x.ruleMatcher?.destination?.namespace} - 服务: {x.ruleMatcher?.destination?.service} + + 命名空间: + {x.ruleMatcher?.destination?.namespace} + + + 服务: + {x.ruleMatcher?.destination?.service} + {x.ruleMatcher?.destination?.method?.value && ( - 接口: {LimitMethodTypeMap[x.ruleMatcher?.destination?.method?.type]} + 接口: + {LimitMethodTypeMap[x.ruleMatcher?.destination?.method?.type]} {x.ruleMatcher?.destination?.method?.value} )} @@ -68,7 +92,7 @@ export default (props: DuckCmpProps): Column { return ( <> @@ -80,7 +104,7 @@ export default (props: DuckCmpProps): Column { return ( <> @@ -91,25 +115,25 @@ export default (props: DuckCmpProps): Column { return ( { dispatch(creators.toggle(x)) }} /> { const type = checkRuleType(x?.level) router.navigate(`/circuitBreaker-create?id=${x.id}&type=${type}`) }} /> { dispatch(creators.remove(x)) }} diff --git a/web/src/polaris/administration/breaker/operations/Create.tsx b/web/src/polaris/administration/breaker/operations/Create.tsx index fa2bc5d7..7a77f0b0 100644 --- a/web/src/polaris/administration/breaker/operations/Create.tsx +++ b/web/src/polaris/administration/breaker/operations/Create.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { DuckCmpProps, purify } from 'saga-duck' import DetailPage from '@src/polaris/common/duckComponents/DetailPage' @@ -118,19 +120,19 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) store={store} duck={duck} dispatch={dispatch} - title={composedId?.id ? '编辑熔断规则' : '新建熔断规则'} + title={composedId?.id ? t('编辑熔断规则') : t('新建熔断规则')} backRoute={backRoute} >
- + - + - +
)
- 主调服务 + 主调服务
- + - + { @@ -173,24 +179,31 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) type={'simulate'} appearance={'button'} matchButtonWidth - placeholder='请选择命名空间' + placeholder={t('请选择命名空间')} style={{ width: '80%', maxWidth: '600px' }} /> - + { return o.namespace === sourceNamespace.getValue() }) || []), ]), ]} - tips='没有匹配的服务名称' + tips={t('没有匹配的服务名称')} onChange={value => { sourceService.setValue(value) }} @@ -198,7 +211,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) {ref => ( { sourceService.setValue(value) }} @@ -214,17 +227,17 @@ export default purify(function CustomRoutePage(props: DuckCmpProps)
- 目标服务 + 目标服务
- + - + { @@ -240,19 +253,21 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) type={'simulate'} appearance={'button'} matchButtonWidth - placeholder='请选择命名空间' + placeholder={t('请选择命名空间')} style={{ width: '80%', maxWidth: '600px' }} /> - + ) }) || []), ]), ]} - tips='没有匹配的服务名称' + tips={t('没有匹配的服务名称')} onChange={value => { destinationService.setValue(value) }} @@ -271,7 +286,9 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) { destinationService.setValue(value) @@ -283,10 +300,10 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) {level.getValue() === BreakLevelType.Method && ( - + ) - +
-
错误判断条件
- 满足以下任意应答条件的请求会被标识为错误请求 +
+ 错误判断条件 +
+ + 满足以下任意应答条件的请求会被标识为错误请求 +
@@ -336,7 +357,9 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) {inputType.getValue() === ErrorConditionType.DELAY && ( - 超过 + + 超过 + )} {inputType.getValue() !== ErrorConditionType.DELAY && ( @@ -351,7 +374,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) @@ -382,8 +405,12 @@ export default purify(function CustomRoutePage(props: DuckCmpProps)
-
熔断触发条件
- 满足以下任意条件可触发熔断 +
+ 熔断触发条件 +
+ + 满足以下任意条件可触发熔断 +
@@ -426,7 +453,12 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) hideButton /> - + { @@ -438,9 +470,9 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) )
-
熔断粒度
- 熔断触发时影响的资源粒度 +
+ 熔断粒度 +
+ + 熔断触发时影响的资源粒度 +
@@ -522,15 +558,17 @@ export default purify(function CustomRoutePage(props: DuckCmpProps)
-
熔断恢复
+
+ 熔断恢复 +
- 经过熔断时长后,会触发熔断恢复机制,若符合预期,则结束熔断;否则重新回到熔断阶段 + 经过熔断时长后,会触发熔断恢复机制,若符合预期,则结束熔断;否则重新回到熔断阶段
- + { @@ -540,9 +578,9 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) hideButton /> - + - 当满足 + 当满足 { @@ -551,7 +589,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) size={'m'} hideButton /> - 个连续成功请求后恢复 + 个连续成功请求后恢复 @@ -561,17 +599,19 @@ export default purify(function CustomRoutePage(props: DuckCmpProps)
- 开启主动探测时,客户端将会根据您配置的探测规则对目标被调服务进行探测; - 主动探测请求与业务调用合并判断熔断恢复(如未匹配到探测规则,则不会生效); - 未开启主动探测时,会仅根据业务调用判断熔断恢复。 + + 开启主动探测时,客户端将会根据您配置的探测规则对目标被调服务进行探测; + 主动探测请求与业务调用合并判断熔断恢复(如未匹配到探测规则,则不会生效); + 未开启主动探测时,会仅根据业务调用判断熔断恢复。 + - 查看主动探测规则 + 查看主动探测规则 @@ -581,19 +621,23 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) {ServiceLevelType.indexOf(level.getValue() as any) > -1 && ( - + {fallbackConfigEnable.getValue() && (
-
自定义响应
- 熔断触发后的降级响应策略 +
+ 自定义响应 +
+ + 熔断触发后的降级响应策略 +
- + { @@ -608,11 +652,11 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) const { key, value } = item.getFields(['key', 'value']) return ( - +
diff --git a/web/src/polaris/administration/breaker/operations/CreateDuck.ts b/web/src/polaris/administration/breaker/operations/CreateDuck.ts index 7f67219b..75f2d6a7 100644 --- a/web/src/polaris/administration/breaker/operations/CreateDuck.ts +++ b/web/src/polaris/administration/breaker/operations/CreateDuck.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { createToPayload, reduceFromPayload } from 'saga-duck' import DetailPage from '@src/polaris/common/ducks/DetailPage' import Form from '@src/polaris/common/ducks/Form' @@ -207,10 +208,10 @@ export default class CircuitBreakerCreatePageDuck extends DetailPage { const validator = Form.combineValidators({ name(v) { if (!v) { - return '请填写路由规则名称' + return t('请填写路由规则名称') } if (!/^[a-zA-Z0-9-_]([a-zA-Z0-9-_]{1,64})?$/.test(v)) { - return '名称只能含有数字,字母,下划线及中划线' + return t('名称只能含有数字,字母,下划线及中划线') } }, ruleMatcher(v, values) { @@ -218,31 +219,31 @@ const validator = Form.combineValidators({ source: { namespace(v) { if (!v) { - return '请选择命名空间' + return t('请选择命名空间') } }, service(v) { if (!v) { - return '请选择服务名' + return t('请选择服务名') } }, }, destination: { namespace(v) { if (!v) { - return '请选择命名空间' + return t('请选择命名空间') } }, service(v) { if (!v) { - return '请选择服务名' + return t('请选择服务名') } }, method: { value(v) { if (values?.level !== BreakLevelType.Method) return if (!v) { - return '请输入接口名' + return t('请输入接口名') } }, }, @@ -254,7 +255,7 @@ const validator = Form.combineValidators({ condition: { value(v) { if (!v) { - return '请输入条件' + return t('请输入条件') } }, }, @@ -262,7 +263,7 @@ const validator = Form.combineValidators({ ], level(v) { if (!v) { - return '请选择熔断粒度' + return t('请选择熔断粒度') } }, fallbackConfig(v, values) { @@ -273,13 +274,13 @@ const validator = Form.combineValidators({ key(v) { if (!values.fallbackConfig.enable) return if (!v) { - return '请输入键' + return t('请输入键') } }, value(v) { if (!values.fallbackConfig.enable) return if (!v) { - return '请输入值' + return t('请输入值') } }, }, diff --git a/web/src/polaris/administration/breaker/types.ts b/web/src/polaris/administration/breaker/types.ts index 2fc9ad10..31c7fedd 100644 --- a/web/src/polaris/administration/breaker/types.ts +++ b/web/src/polaris/administration/breaker/types.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { KeyValuePair } from '@src/polaris/configuration/fileGroup/types' export interface CircuitBreakerRule { @@ -65,8 +66,8 @@ export enum ErrorConditionType { DELAY = 'DELAY', } export const ErrorConditionMap = { - [ErrorConditionType.DELAY]: '时延', - [ErrorConditionType.RET_CODE]: '返回码', + [ErrorConditionType.DELAY]: t('时延'), + [ErrorConditionType.RET_CODE]: t('返回码'), } export const ErrorConditionOptions = Object.entries(ErrorConditionMap).map(([key, value]) => ({ text: value, @@ -77,8 +78,8 @@ export enum TriggerType { CONSECUTIVE_ERROR = 'CONSECUTIVE_ERROR', } export const TriggerTypeMap = { - [TriggerType.CONSECUTIVE_ERROR]: { text: '连续错误数', unit: '个' }, - [TriggerType.ERROR_RATE]: { text: '错误率', unit: '%' }, + [TriggerType.CONSECUTIVE_ERROR]: { text: t('连续错误数'), unit: t('个') }, + [TriggerType.ERROR_RATE]: { text: t('错误率'), unit: '%' }, } export const TriggerTypeOptions = Object.entries(TriggerTypeMap).map(([key, value]) => ({ text: value.text, @@ -91,10 +92,10 @@ export enum BreakLevelType { Service = 'SERVICE', } export const BreakLevelMap = { - [BreakLevelType.Instance]: '实例', - [BreakLevelType.Group]: '实例分组', - [BreakLevelType.Method]: '接口', - [BreakLevelType.Service]: '服务', + [BreakLevelType.Instance]: t('实例'), + [BreakLevelType.Group]: t('实例分组'), + [BreakLevelType.Method]: t('接口'), + [BreakLevelType.Service]: t('服务'), } export const BreakLevelSearchParamMap = { [BreakLevelType.Instance]: 4, @@ -128,7 +129,7 @@ export const checkRuleType = level => ? BreakerType.Interface : BreakerType.FaultDetect export const FaultDetectTabs = [ - { id: BreakerType.Service, label: '服务级熔断' }, - { id: BreakerType.Interface, label: '节点级熔断' }, - { id: BreakerType.FaultDetect, label: '主动探测' }, + { id: BreakerType.Service, label: t('服务级熔断') }, + { id: BreakerType.Interface, label: t('节点级熔断') }, + { id: BreakerType.FaultDetect, label: t('主动探测') }, ] diff --git a/web/src/polaris/administration/dynamicRoute/customRoute/Page.tsx b/web/src/polaris/administration/dynamicRoute/customRoute/Page.tsx index 445dcfd3..76116535 100644 --- a/web/src/polaris/administration/dynamicRoute/customRoute/Page.tsx +++ b/web/src/polaris/administration/dynamicRoute/customRoute/Page.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { DuckCmpProps, purify } from 'saga-duck' import CustomRouteDuck from './PageDuck' @@ -22,27 +24,27 @@ function getTagAttributes() { { type: 'input', key: TagSearchType.RuleName, - name: '规则名', + name: t('规则名'), }, { type: 'input', key: TagSearchType.SourceNamespace, - name: '主调命名空间', + name: t('主调命名空间'), }, { type: 'input', key: TagSearchType.SourceService, - name: '主调服务', + name: t('主调服务'), }, { type: 'input', key: TagSearchType.DestNamespace, - name: '被调命名空间', + name: t('被调命名空间'), }, { type: 'input', key: TagSearchType.DestService, - name: '被调服务', + name: t('被调服务'), }, ] } @@ -67,7 +69,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps} @@ -77,7 +79,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps - 新建路由规则 + 新建路由规则 } right={ @@ -90,7 +92,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps handlers.changeTags(value)} - tips={'请选择条件进行过滤'} + tips={t('请选择条件进行过滤')} hideHelp={true} /> @@ -111,7 +113,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps handlers.changeStatus(value), all: { value: '', - text: '全部', + text: t('全部'), }, options: StatusOptions, }), diff --git a/web/src/polaris/administration/dynamicRoute/customRoute/PageDuck.tsx b/web/src/polaris/administration/dynamicRoute/customRoute/PageDuck.tsx index 1af5aad0..9b111b78 100644 --- a/web/src/polaris/administration/dynamicRoute/customRoute/PageDuck.tsx +++ b/web/src/polaris/administration/dynamicRoute/customRoute/PageDuck.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import { createToPayload, reduceFromPayload } from 'saga-duck' import router from '@src/polaris/common/util/router' import { takeLatest } from 'redux-saga-catch' @@ -180,8 +182,10 @@ export default class CustomRouteDuck extends GridPageDuck { watch: types.DELETE, fn: function*(item) { const confirm = yield Modal.confirm({ - message: `确认删除路由规则 ${item.name} 吗?`, - description: '删除后,无法恢复', + message: t('确认删除路由规则 {{attr0}} 吗?', { + attr0: item.name, + }), + description: t('删除后,无法恢复'), }) if (confirm) { yield deleteCustomRoute([{ id: item.id }]) @@ -194,10 +198,13 @@ export default class CustomRouteDuck extends GridPageDuck { type: OperationType.SINGLE, watch: types.SWITCH_STATUS, fn: function*(item: any) { - const ops = item.swtichStatusAction === SwitchStatusAction.disable ? '禁用' : '启用' + const ops = item.swtichStatusAction === SwitchStatusAction.disable ? t('禁用') : t('启用') const disable = item.swtichStatusAction === SwitchStatusAction.disable ? true : false const confirm = yield Modal.confirm({ - message: `确认${ops}路由规则 ${item.name} 吗?`, + message: t('确认{{attr0}}路由规则 {{attr1}} 吗?', { + attr0: ops, + attr1: item.name, + }), }) if (confirm) { if (disable) { @@ -233,7 +240,7 @@ export default class CustomRouteDuck extends GridPageDuck { attr: { type: 'input', key: TagSearchType.RuleName, - name: '规则名', + name: t('规则名'), }, } }) diff --git a/web/src/polaris/administration/dynamicRoute/customRoute/detail/Page.tsx b/web/src/polaris/administration/dynamicRoute/customRoute/detail/Page.tsx index d884fcca..0b059e38 100644 --- a/web/src/polaris/administration/dynamicRoute/customRoute/detail/Page.tsx +++ b/web/src/polaris/administration/dynamicRoute/customRoute/detail/Page.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { DuckCmpProps, purify } from 'saga-duck' import DetailPage from '@src/polaris/common/duckComponents/DetailPage' @@ -38,8 +40,8 @@ insertCSS( `, ) -const formatNamespace = value => (value === '*' ? '全部命名空间' : value) -const formatService = value => (value === '*' ? '全部服务' : value) +const formatNamespace = value => (value === '*' ? t('全部命名空间') : value) +const formatService = value => (value === '*' ? t('全部服务') : value) export default purify(function CustomRoutePage(props: DuckCmpProps) { const { duck, store, dispatch } = props @@ -64,16 +66,16 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) {
- + {name || '-'} - + {description || '-'} - + {priority} - +
) {
- 主调服务 + 主调服务 - 主调请求按照匹配规则匹配成功后,将按照当前规则进行目标服务路由 + 主调请求按照匹配规则匹配成功后,将按照当前规则进行目标服务路由
- + {formatNamespace(source?.namespace)} - + {formatService(source?.service)} @@ -112,19 +114,19 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) {
- 被调服务 + 被调服务 - 请求会按照规则路由到目标服务分组 + 请求会按照规则路由到目标服务分组
- + {formatNamespace(destination?.namespace)} - + {formatService(destination?.service)} @@ -134,17 +136,26 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) { - + {rules?.map((rule, index) => { const { sources, destinations } = rule return ( - {`规则${index + 1}`}}> + + {t('规则{{attr0}}', { + attr0: index + 1, + })} + + } + > - 来源服务的请求满足以下匹配条件 + 来源服务的请求满足以下匹配条件
{sources?.[0]?.arguments?.length > 0 && ( @@ -155,7 +166,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) { columns={[ { key: 'type', - header: '类型', + header: t('类型'), render: item => { const { type } = item @@ -168,7 +179,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) { }, { key: 'key', - header: '键', + header: t('键'), render: item => { const { key } = item return ( @@ -180,7 +191,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) { }, { key: 'value_type', - header: '匹配方式', + header: t('匹配方式'), width: 80, render: item => { const { value_type } = item @@ -193,7 +204,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) { }, { key: 'value', - header: '值', + header: t('值'), render: item => { const { value } = item return ( @@ -208,7 +219,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) { )}
- 将转发至目标服务的以下实例分组 + 将转发至目标服务的以下实例分组
{destinations?.length > 0 && ( @@ -219,7 +230,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) { columns={[ { key: 'labels', - header: '实例标签', + header: t('实例标签'), render: item => { const { labels } = item return ( @@ -238,7 +249,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) { }, { key: 'weight', - header: '权重', + header: t('权重'), render: item => { const { weight } = item return weight @@ -246,10 +257,10 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) { }, { key: 'isolate', - header: '是否隔离', + header: t('是否隔离'), render: item => { const { isolate } = item - return isolate ? '是' : '否' + return isolate ? t('是') : t('否') }, }, ]} diff --git a/web/src/polaris/administration/dynamicRoute/customRoute/getColumns.tsx b/web/src/polaris/administration/dynamicRoute/customRoute/getColumns.tsx index a5990c24..280c8d59 100644 --- a/web/src/polaris/administration/dynamicRoute/customRoute/getColumns.tsx +++ b/web/src/polaris/administration/dynamicRoute/customRoute/getColumns.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import * as React from 'react' import AccessLimitingDuck from './PageDuck' import { Text, Copy } from 'tea-component' @@ -16,7 +18,7 @@ export default ( return [ { key: 'idName', - header: 'ID/规则名', + header: t('ID/规则名'), width: 280, render: x => ( <> @@ -33,43 +35,64 @@ export default ( }, { key: 'enable', - header: '状态', - render: x => (x.enable ? 已启用 : 未启用), + header: t('状态'), + render: x => + x.enable ? ( + + 已启用 + + ) : ( + + 未启用 + + ), }, { key: 'description', - header: '描述', + header: t('描述'), render: x => x.description || '-', }, { key: 'source', - header: '主调服务', + header: t('主调服务'), render: x => { const { namespace, service } = x?.routing_config?.rules?.[0]?.sources?.[0] || {} return ( <> - 命名空间:{namespace || '-'} - 服务:{service || '-'} + + 命名空间: + {namespace || '-'} + + + 服务: + {service || '-'} + ) }, }, { key: 'destination', - header: '被调服务', + header: t('被调服务'), render: x => { const { namespace, service } = x?.routing_config?.rules?.[0]?.destinations?.[0] || {} return ( <> - 命名空间:{namespace || '-'} - 服务:{service || '-'} + + 命名空间: + {namespace || '-'} + + + 服务: + {service || '-'} + ) }, }, { key: 'ctimeMtime', - header: '创建时间/修改时间', + header: t('创建时间/修改时间'), render: x => ( <> @@ -82,7 +105,7 @@ export default ( }, { key: 'etime', - header: '启用时间', + header: t('启用时间'), render: x => ( <> {x.etime || '-'} @@ -91,7 +114,7 @@ export default ( }, { key: 'action', - header: '操作', + header: t('操作'), render: x => { const actions: { id: string @@ -100,7 +123,7 @@ export default ( }[] = [ { id: 'switchStatus', - text: x.enable ? '禁用' : '启用', + text: x.enable ? t('禁用') : t('启用'), fn: dispatch => { const swtichStatusAction = x.enable ? SwitchStatusAction.disable : SwitchStatusAction.start dispatch(creators.switchStatus(x.id, x.name, swtichStatusAction)) @@ -108,14 +131,14 @@ export default ( }, { id: 'modify', - text: '编辑', + text: t('编辑'), fn: dispatch => { dispatch(creators.modify(x)) }, }, { id: 'remove', - text: '删除', + text: t('删除'), fn: dispatch => { dispatch(creators.delete(x)) }, diff --git a/web/src/polaris/administration/dynamicRoute/customRoute/model.ts b/web/src/polaris/administration/dynamicRoute/customRoute/model.ts index 32c86bed..01a66f03 100644 --- a/web/src/polaris/administration/dynamicRoute/customRoute/model.ts +++ b/web/src/polaris/administration/dynamicRoute/customRoute/model.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { apiRequest, getApiRequest, putApiRequest } from '@src/polaris/common/util/apiRequest' export interface CustomRoute { diff --git a/web/src/polaris/administration/dynamicRoute/customRoute/operations/Create.tsx b/web/src/polaris/administration/dynamicRoute/customRoute/operations/Create.tsx index 040580e5..5273029d 100644 --- a/web/src/polaris/administration/dynamicRoute/customRoute/operations/Create.tsx +++ b/web/src/polaris/administration/dynamicRoute/customRoute/operations/Create.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { DuckCmpProps, purify, useDuck } from 'saga-duck' import DetailPage from '@src/polaris/common/duckComponents/DetailPage' @@ -144,7 +146,16 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) ]) const keyValidate = keyField.getTouched() && keyField.getError() const labelList = [ - ...(keyField.getValue() ? [{ text: `(输入值)${keyField.getValue()}`, value: keyField.getValue() }] : []), + ...(keyField.getValue() + ? [ + { + text: t('(输入值){{attr0}}', { + attr0: keyField.getValue(), + }), + value: keyField.getValue(), + }, + ] + : []), ...filteredLabelList.filter(item => (keyField.getValue() ? item.text.indexOf(keyField.getValue()) > -1 : true)), ] let keyComponent @@ -152,7 +163,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) keyComponent = ( { if (value !== keyField.getValue()) { valueField.setValue('') @@ -173,7 +184,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) } keyField.setValue(value) }} - placeholder={'请输入标签键'} + placeholder={t('请输入标签键')} size={'full'} /> )} @@ -190,7 +201,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) keyComponent = } else { keyComponent = ( - keyField.setValue(key)} /> + keyField.setValue(key)} /> ) } return ( @@ -218,7 +229,16 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) const labelList = type === 'source' ? sourceLabelList : destinationLabelList const valueOptions = labelList.find(item => item.value === keyField.getValue())?.valueOptions || [] const options = [ - ...(valueField.getValue() ? [{ text: `(输入值)${valueField.getValue()}`, value: valueField.getValue() }] : []), + ...(valueField.getValue() + ? [ + { + text: t('(输入值){{attr0}}', { + attr0: valueField.getValue(), + }), + value: valueField.getValue(), + }, + ] + : []), ...valueOptions.filter(item => (valueField.getValue() ? item.text.indexOf(valueField.getValue()) > -1 : true)), ] let valueComponent @@ -252,7 +272,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) valueComponent = ( { valueField.setValue(value) }} @@ -264,7 +284,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) onChange={value => { valueField.setValue(value) }} - placeholder={'请输入标签值'} + placeholder={t('请输入标签值')} size={'full'} disabled={value_type.getValue() === RoutingValueType.PARAMETER} /> @@ -273,7 +293,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) ) } else { valueComponent = ( - valueField.setValue(value)} /> + valueField.setValue(value)} /> ) } return ( @@ -369,11 +389,11 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) disabled={!labelField.getValue()?.type || !labelField.getValue()?.key || !labelField.getValue()?.value} tooltip={ !labelField.getValue()?.type || !labelField.getValue()?.key || !labelField.getValue()?.value - ? '请输入完整标签' + ? t('请输入完整标签') : '' } > - {'确认'} + {t('确认')} } > @@ -404,19 +424,19 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) store={store} duck={duck} dispatch={dispatch} - title={composedId?.id ? '编辑服务路由规则' : '新建服务路由规则'} + title={composedId?.id ? t('编辑服务路由规则') : t('新建服务路由规则')} backRoute={backRoute} >
- + - + - +
) style={{ position: 'absolute', left: 'calc(50% + -14px)', top: '-14px' }} > - 点击切换主被调服务 + 点击切换主被调服务
@@ -449,20 +469,24 @@ export default purify(function CustomRoutePage(props: DuckCmpProps)
- 主调服务 + 主调服务 - 主调请求按照匹配规则匹配成功后,将按照当前规则进行目标服务路由 + 主调请求按照匹配规则匹配成功后,将按照当前规则进行目标服务路由
- + { @@ -547,19 +578,21 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) type={'simulate'} appearance={'button'} matchButtonWidth - placeholder='请选择命名空间' + placeholder={t('请选择命名空间')} size='m' /> - + ) }) || []), ]), ]} - tips='没有匹配的服务名称' + tips={t('没有匹配的服务名称')} onChange={value => { destinationService.setValue(value) }} @@ -578,7 +611,9 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) { destinationService.setValue(value) @@ -595,7 +630,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps)
- + { const source = context.source.index @@ -638,7 +673,9 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) icon={'drop'} onClick={() => setIsDragging(!isDragging)} > - {`规则${index + 1}`} + {t('规则{{attr0}}', { + attr0: index + 1, + })}
} right={ @@ -666,7 +703,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) {!isDragging && ( - 来源服务的请求满足以下匹配条件 + 来源服务的请求满足以下匹配条件
{argumentsField?.getValue()?.length > 0 && ( @@ -682,7 +719,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) type='link' onClick={() => argumentsField.asArray().push(getEmptyLabel())} > - 添加 + 添加
} @@ -690,7 +727,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) columns={[ { key: 'type', - header: '类型', + header: t('类型'), width: 200, render: item => { const { type, key } = item.getFields(['type', 'key']) @@ -778,7 +815,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) )} - 将转发至目标服务的一下实例分组 + 将转发至目标服务的一下实例分组
{ruleDestinations?.getValue()?.length > 0 && ( @@ -789,7 +826,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) columns={[ { key: 'labels', - header: '实例标签', + header: t('实例标签'), render: (item, _, recordIndex) => { const { labels } = item.getFields(['labels']) const validate = labels.getTouched() && labels.getError() @@ -830,8 +867,8 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) key: 'weight', header: ( <> - 权重 - + 权重 + @@ -844,7 +881,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) }, { key: 'isolate', - header: '是否隔离', + header: t('是否隔离'), width: 100, render: item => { const { isolate } = item.getFields(['isolate']) @@ -884,7 +921,7 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) type='link' onClick={() => ruleDestinations.asArray().push(getEmptyDestination())} > - 添加 + 添加
@@ -896,7 +933,13 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) return mainComponent } return ( - + {provided => (
{mainComponent} @@ -913,17 +956,17 @@ export default purify(function CustomRoutePage(props: DuckCmpProps)
- + diff --git a/web/src/polaris/administration/dynamicRoute/customRoute/operations/CreateDuck.ts b/web/src/polaris/administration/dynamicRoute/customRoute/operations/CreateDuck.ts index d80c916a..27847c48 100644 --- a/web/src/polaris/administration/dynamicRoute/customRoute/operations/CreateDuck.ts +++ b/web/src/polaris/administration/dynamicRoute/customRoute/operations/CreateDuck.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { createToPayload, reduceFromPayload } from 'saga-duck' import DetailPage from '@src/polaris/common/ducks/DetailPage' import Form from '@src/polaris/common/ducks/Form' @@ -166,7 +167,9 @@ export default class CustomRouteCreatePageDuck extends DetailPage { })), })) return { - name: `规则${index}`, + name: t('规则{{attr0}}', { + attr0: index, + }), sources: handledSources, destinations: handledDestinations, } @@ -363,30 +366,30 @@ export interface Values { const validator = Form.combineValidators({ name(v) { if (!v) { - return '请填写路由规则名称' + return t('请填写路由规则名称') } }, source: { namespace(v) { if (!v) { - return '请选择命名空间' + return t('请选择命名空间') } }, service(v) { if (!v) { - return '请选择服务名' + return t('请选择服务名') } }, }, destination: { namespace(v) { if (!v) { - return '请选择命名空间' + return t('请选择命名空间') } }, service(v) { if (!v) { - return '请选择服务名' + return t('请选择服务名') } }, }, @@ -398,15 +401,15 @@ const validator = Form.combineValidators({ { key(v) { if (!v) { - return '请输入key值' + return t('请输入key值') } }, value(v, data) { if (!v && data.type === RoutingArgumentsType.CALLER_IP) { - return '请输入IP' + return t('请输入IP') } if (!v && data.type !== RoutingArgumentsType.CALLER_IP) { - return '请输入value值' + return t('请输入value值') } }, }, @@ -417,7 +420,7 @@ const validator = Form.combineValidators({ { labels(v) { if (!v.length) { - return '请输入标签分组' + return t('请输入标签分组') } }, }, @@ -449,7 +452,7 @@ export class RouteCreateDuck extends Form { }, rules: [ { - name: '规则1', + name: t('规则1'), sources: [ { service: '*', diff --git a/web/src/polaris/administration/dynamicRoute/customRoute/types.ts b/web/src/polaris/administration/dynamicRoute/customRoute/types.ts index 83ce495f..5b067aef 100644 --- a/web/src/polaris/administration/dynamicRoute/customRoute/types.ts +++ b/web/src/polaris/administration/dynamicRoute/customRoute/types.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' // 接口类型 // 接口类型 export enum RouteLabelMatchType { @@ -11,27 +12,27 @@ export enum RouteLabelMatchType { export const RouteLabelMatchTypeOptions = [ { value: RouteLabelMatchType.EXACT, - text: '等于', + text: t('等于'), }, { value: RouteLabelMatchType.REGEX, - text: '正则表达式匹配', + text: t('正则表达式匹配'), }, { value: RouteLabelMatchType.NOT_EQUALS, - text: '不等于', + text: t('不等于'), }, { value: RouteLabelMatchType.IN, - text: '包含', + text: t('包含'), }, { value: RouteLabelMatchType.NOT_IN, - text: '不包含', + text: t('不包含'), }, { value: RouteLabelMatchType.RANGE, - text: '范围表达式', + text: t('范围表达式'), }, ] export const RouteLabelTextMap = RouteLabelMatchTypeOptions.reduce((map, curr) => { @@ -55,12 +56,12 @@ export enum RoutingValueType { PARAMETER = 'PARAMETER', } export const RoutingValueTextMap = { - [RoutingValueType.TEXT]: '值', - [RoutingValueType.PARAMETER]: '变量', + [RoutingValueType.TEXT]: t('值'), + [RoutingValueType.PARAMETER]: t('变量'), } export const RoutingValueTypeOptions = [ { - text: '值', + text: t('值'), value: RoutingValueType.TEXT, }, // { @@ -71,31 +72,31 @@ export const RoutingValueTypeOptions = [ export const RoutingArgumentsTypeOptions = [ { value: RoutingArgumentsType.CUSTOM, - text: '自定义', + text: t('自定义'), }, { value: RoutingArgumentsType.HEADER, - text: '请求头(HEADER)', + text: t('请求头(HEADER)'), }, { value: RoutingArgumentsType.COOKIE, - text: '请求Cookie(COOKIE)', + text: t('请求Cookie(COOKIE)'), }, { value: RoutingArgumentsType.QUERY, - text: '请求参数(QUERY)', + text: t('请求参数(QUERY)'), }, { value: RoutingArgumentsType.METHOD, - text: '方法(METHOD)', + text: t('方法(METHOD)'), }, { value: RoutingArgumentsType.CALLER_IP, - text: '主调IP', + text: t('主调IP'), }, { value: RoutingArgumentsType.PATH, - text: '路径', + text: t('路径'), }, ] export const RouteArgumentTextMap = RoutingArgumentsTypeOptions.reduce((map, curr) => { diff --git a/web/src/polaris/administration/dynamicRoute/graypublish/Page.tsx b/web/src/polaris/administration/dynamicRoute/graypublish/Page.tsx index 810c35ff..4ff7300e 100644 --- a/web/src/polaris/administration/dynamicRoute/graypublish/Page.tsx +++ b/web/src/polaris/administration/dynamicRoute/graypublish/Page.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { Layout, Card, Tabs, TabPanel, Text } from 'tea-component' import insertCSS from '@src/polaris/common/helpers/insertCSS' @@ -42,7 +44,7 @@ function TabContentComp(props: RouteTabContentInfo) { target='_blank' rel='noreferrer' > - 操作指引 + 操作指引 ))} @@ -62,7 +64,7 @@ function TabContentComp(props: RouteTabContentInfo) { target='_blank' rel='noreferrer' > - 操作指引 + 操作指引 ))} @@ -80,7 +82,7 @@ export default function TestEnvRoutePage() { - + {tabs.map(tab => { diff --git a/web/src/polaris/administration/dynamicRoute/graypublish/TabConfig.tsx b/web/src/polaris/administration/dynamicRoute/graypublish/TabConfig.tsx index 40df4f3c..fd64dddd 100644 --- a/web/src/polaris/administration/dynamicRoute/graypublish/TabConfig.tsx +++ b/web/src/polaris/administration/dynamicRoute/graypublish/TabConfig.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { List, Text } from 'tea-component' @@ -24,15 +26,15 @@ export interface ImageLinks { linkAddress: string } export const tabs = [ - { id: RouteTabId.BlueGreen, label: '蓝绿发布' }, - { id: RouteTabId.Canary, label: '金丝雀发布' }, - { id: RouteTabId.FullLinkGray, label: '全链路灰度发布' }, + { id: RouteTabId.BlueGreen, label: t('蓝绿发布') }, + { id: RouteTabId.Canary, label: t('金丝雀发布') }, + { id: RouteTabId.FullLinkGray, label: t('全链路灰度发布') }, ] export const tabConfigs: RouteTabConfigInfo = { [RouteTabId.BlueGreen]: { imagePath: 'static/img/bluegreen-publish.png', - alt: '蓝绿发布路由', + alt: t('蓝绿发布路由'), title: '', imageLinks: [ { @@ -64,10 +66,11 @@ export const tabConfigs: RouteTabConfigInfo = { }, [RouteTabId.Canary]: { imagePath: 'static/img/canary-publish.png', - alt: '金丝雀发布路由', - title: '金丝雀发布', - description: + alt: t('金丝雀发布路由'), + title: t('金丝雀发布'), + description: t( '针对是单个服务的服务灰度验证,金丝雀发布允许引流一小部分流量到服务的新版本(比如按灰度用户引流),充分验证微服务新版本的稳定性,验证没问题后,再升级原来的稳定版本。', + ), imageLinks: [ { style: { top: '28.7%', left: '29.8%' }, @@ -95,7 +98,7 @@ export const tabConfigs: RouteTabConfigInfo = { imagePath: [ { path: 'static/img/full-link-gray-publish-scene1.png', - title: '场景一', + title: t('场景一'), imageLinks: [ { style: { top: '27.2%', left: '29.8%' }, @@ -126,7 +129,7 @@ export const tabConfigs: RouteTabConfigInfo = { }, { path: 'static/img/full-link-gray-publish-scene2.png', - title: '场景二', + title: t('场景二'), imageLinks: [ { style: { top: '30.9%', left: '29.8%' }, @@ -156,22 +159,28 @@ export const tabConfigs: RouteTabConfigInfo = { ], }, ], - alt: '全链路灰度发布', - title: '全链路灰度发布', + alt: t('全链路灰度发布'), + title: t('全链路灰度发布'), description: ( <> - 微服务架构下,有些开发需求,微服务调用链路上的多个微服务同时发生了改动, - 通常每个微服务都会有灰度环境或分组来接收灰度流量。此时希望通过进入上游灰度环境的流量, - 也能进入下游灰度的环境中,确保1个请求始终在灰度环境中传递,即使这个调用链路上有一些微服务没有灰度环境, - 这些应用请求在下游的时候依然能够回到灰度环境中。 + + 微服务架构下,有些开发需求,微服务调用链路上的多个微服务同时发生了改动, + 通常每个微服务都会有灰度环境或分组来接收灰度流量。此时希望通过进入上游灰度环境的流量, + 也能进入下游灰度的环境中,确保1个请求始终在灰度环境中传递,即使这个调用链路上有一些微服务没有灰度环境, + 这些应用请求在下游的时候依然能够回到灰度环境中。 + - 实现方案的两个场景: + 实现方案的两个场景: - 应用场景一:金丝雀环境和稳定环境有独立的域名进行隔离,实现全链路灰度。 - 应用场景二:使用相同域名,基于请求标签实现全链路灰度。 + + 应用场景一:金丝雀环境和稳定环境有独立的域名进行隔离,实现全链路灰度。 + + + 应用场景二:使用相同域名,基于请求标签实现全链路灰度。 + ), diff --git a/web/src/polaris/administration/dynamicRoute/testEnvRoute/Page.tsx b/web/src/polaris/administration/dynamicRoute/testEnvRoute/Page.tsx index 6a835865..1bfb8622 100644 --- a/web/src/polaris/administration/dynamicRoute/testEnvRoute/Page.tsx +++ b/web/src/polaris/administration/dynamicRoute/testEnvRoute/Page.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { Layout, Card, Tabs, TabPanel } from 'tea-component' import insertCSS from '@src/polaris/common/helpers/insertCSS' @@ -64,7 +66,7 @@ export default function TestEnvRoutePage() { - + {tabs.map(tab => { diff --git a/web/src/polaris/administration/dynamicRoute/testEnvRoute/TabConfig.ts b/web/src/polaris/administration/dynamicRoute/testEnvRoute/TabConfig.ts index e83e1aa4..8036b2a1 100644 --- a/web/src/polaris/administration/dynamicRoute/testEnvRoute/TabConfig.ts +++ b/web/src/polaris/administration/dynamicRoute/testEnvRoute/TabConfig.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' enum TabId { client = 'client', dynamic = 'dynamic', @@ -20,15 +21,15 @@ interface TabConfigInfo { } export const tabs = [ - { id: TabId.client, label: '客户端染色' }, - { id: TabId.dynamic, label: '网关动态染色' }, - { id: TabId.static, label: '网关静态染色' }, + { id: TabId.client, label: t('客户端染色') }, + { id: TabId.dynamic, label: t('网关动态染色') }, + { id: TabId.static, label: t('网关静态染色') }, ] export const tabConfigs: TabConfigInfo = { [TabId.client]: { imagePath: 'static/img/testEnvRoute-client.png', - alt: '客户端染色流程指引', + alt: t('客户端染色流程指引'), imageLinks: [ { style: { top: '18.9%', left: '29.8%' }, @@ -44,7 +45,7 @@ export const tabConfigs: TabConfigInfo = { }, [TabId.dynamic]: { imagePath: 'static/img/testEnvRoute-dynamic.png', - alt: '网关动态染色流程指引', + alt: t('网关动态染色流程指引'), imageLinks: [ { style: { top: '18.9%', left: '29.8%' }, @@ -65,7 +66,7 @@ export const tabConfigs: TabConfigInfo = { }, [TabId.static]: { imagePath: 'static/img/testEnvRoute-static.png', - alt: '网关静态染色流程指引', + alt: t('网关静态染色流程指引'), imageLinks: [ { style: { top: '18.9%', left: '29.8%' }, diff --git a/web/src/polaris/alert/Page.tsx b/web/src/polaris/alert/Page.tsx index 3c922d61..95abeeae 100644 --- a/web/src/polaris/alert/Page.tsx +++ b/web/src/polaris/alert/Page.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { DuckCmpProps } from 'saga-duck' import NamespaceDuck from './PageDuck' @@ -20,8 +22,8 @@ insertCSS( export default function ServicePage(props: DuckCmpProps) { const { duck, store, dispatch } = props return ( - }> - + }> + diff --git a/web/src/polaris/alert/PageDuck.ts b/web/src/polaris/alert/PageDuck.ts index 51aa3369..5f2d4b71 100644 --- a/web/src/polaris/alert/PageDuck.ts +++ b/web/src/polaris/alert/PageDuck.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { createToPayload, reduceFromPayload } from 'saga-duck' import GridPageDuck, { Filter as BaseFilter } from '../common/ducks/GridPage' import { AlertInfo } from './types' diff --git a/web/src/polaris/alert/detail/Page.tsx b/web/src/polaris/alert/detail/Page.tsx index 90bc9371..4768d5d6 100644 --- a/web/src/polaris/alert/detail/Page.tsx +++ b/web/src/polaris/alert/detail/Page.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { DuckCmpProps, purify } from 'saga-duck' import DetailPage from '@src/polaris/common/duckComponents/DetailPage' @@ -27,23 +29,23 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) {
- + {alertInfo.name} - - {alertInfo.enable ? '已启用' : '未启用'} + + {alertInfo.enable ? t('已启用') : t('未启用')} - + {MonitorTypeMap[alertInfo.monitor_type] || '-'} - + {alertInfo.modify_time} - + {MetricNameMap[alertInfo.alter_expr?.metrics_name]?.text} {AlterExprMap[alertInfo.alter_expr?.expr]}{' '} @@ -51,23 +53,28 @@ export default purify(function CustomRoutePage(props: DuckCmpProps) { {MetricNameMap[alertInfo.alter_expr?.metrics_name]?.unit} - 持续{alertInfo.alter_expr.for} + 持续 + {alertInfo.alter_expr.for} {AlertTimeIntervalMap[alertInfo.alter_expr.for_unit]} - + - 每隔{`${alertInfo.interval}${AlertTimeIntervalMap[alertInfo.interval_unit]}`}告警一次 + + 每隔 + {`${alertInfo.interval}${AlertTimeIntervalMap[alertInfo.interval_unit]}`} + 告警一次 + - + {alertInfo.topic} - + {alertInfo.message} - + {alertInfo.callback?.info?.url} diff --git a/web/src/polaris/alert/detail/PageDuck.ts b/web/src/polaris/alert/detail/PageDuck.ts index 10c6a992..636ad800 100644 --- a/web/src/polaris/alert/detail/PageDuck.ts +++ b/web/src/polaris/alert/detail/PageDuck.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import DetailPage from '@src/polaris/common/ducks/DetailPage' import { ClsInfo, describeAlertRules } from '../model' import { AlertInfo } from '../types' diff --git a/web/src/polaris/alert/getColumns.tsx b/web/src/polaris/alert/getColumns.tsx index 90d0ad58..9c03c398 100644 --- a/web/src/polaris/alert/getColumns.tsx +++ b/web/src/polaris/alert/getColumns.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import * as React from 'react' import { DuckCmpProps } from 'saga-duck' import AlertPageDuck from './PageDuck' @@ -12,8 +14,8 @@ export default ({ duck: { creators } }: DuckCmpProps): Column ( + header: t('策略ID/名称'), + render: x => ( <> {x.id} @@ -24,20 +26,21 @@ export default ({ duck: { creators } }: DuckCmpProps): Column {MonitorTypeMap[x.monitor_type] || '-'}, + header: t('监控类型'), + render: x => {MonitorTypeMap[x.monitor_type] || '-'}, }, { key: 'rules', - header: '触发条件', - render: (x) => ( + header: t('触发条件'), + render: x => ( <> {MetricNameMap[x.alter_expr?.metrics_name]?.text} {AlterExprMap[x.alter_expr?.expr]} {x.alter_expr?.value} {MetricNameMap[x.alter_expr?.metrics_name]?.unit} - 持续{x.alter_expr.for} + 持续 + {x.alter_expr.for} {AlertTimeIntervalMap[x.alter_expr.for_unit]} @@ -45,13 +48,19 @@ export default ({ duck: { creators } }: DuckCmpProps): Column 每隔{`${x.interval}${AlertTimeIntervalMap[x.interval_unit]}`}告警一次, + header: t('告警规则'), + render: x => ( + + 每隔 + {`${x.interval}${AlertTimeIntervalMap[x.interval_unit]}`} + 告警一次 + + ), }, { key: 'ctime', - header: '创建时间', - render: (x) => ( + header: t('创建时间'), + render: x => ( <> {x.create_time} {x.modify_time} @@ -60,18 +69,18 @@ export default ({ duck: { creators } }: DuckCmpProps): Column { + header: t('操作'), + render: x => { return ( - dispatch(creators.toggle(x))} tip={x.enable ? '禁用' : '启用'}> - {x.enable ? '禁用' : '启用'} + dispatch(creators.toggle(x))} tip={x.enable ? t('禁用') : t('启用')}> + {x.enable ? t('禁用') : t('启用')} - dispatch(creators.edit(x))} tip={'编辑'}> - {'编辑'} + dispatch(creators.edit(x))} tip={t('编辑')}> + {t('编辑')} - dispatch(creators.remove(x))} tip={'删除'}> - {'删除'} + dispatch(creators.remove(x))} tip={t('删除')}> + {t('删除')} ) diff --git a/web/src/polaris/alert/operation/Create.tsx b/web/src/polaris/alert/operation/Create.tsx index 23ca0606..abfd2386 100644 --- a/web/src/polaris/alert/operation/Create.tsx +++ b/web/src/polaris/alert/operation/Create.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { DuckCmpProps, purify } from 'saga-duck' import Duck from './CreateDuck' @@ -22,7 +24,13 @@ export default function Create(props: DuckCmpProps) { } const data = selectors.data(store) return ( - + ) @@ -59,10 +67,10 @@ const CreateForm = purify(function CreateForm(props: DuckCmpProps) { return ( <>
- + - + - + - {'当'} + {t('当')} ) { appearance={'button'} > - + - + - + { diff --git a/web/src/polaris/alert/operation/CreateDuck.ts b/web/src/polaris/alert/operation/CreateDuck.ts index 9a537bec..e644e99a 100644 --- a/web/src/polaris/alert/operation/CreateDuck.ts +++ b/web/src/polaris/alert/operation/CreateDuck.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { put, select } from 'redux-saga/effects' import FormDialog from '@src/polaris/common/ducks/FormDialog' import { resolvePromise } from '@src/polaris/common/helpers/saga' @@ -137,41 +138,41 @@ class CreateForm extends Form { } const validator = CreateForm.combineValidators({ name(v) { - if (!v) return '请填写名称' + if (!v) return t('请填写名称') }, monitor_type(v) { - if (!v) return '请填写监控类型' + if (!v) return t('请填写监控类型') }, alter_expr(v, meta) { const res = CreateForm.combineValidators({ metrics_name(v) { - if (!v) return '请选择请求指标' + if (!v) return t('请选择请求指标') }, expr(v) { - if (!v) return '请选择表达式' + if (!v) return t('请选择表达式') }, value(v) { - if (!v) return '请选择阈值' + if (!v) return t('请选择阈值') }, for(v) { - if (!v) return '请输入持续时长' + if (!v) return t('请输入持续时长') }, for_unit(v) { - if (!v) return '请选择持续时长单位' + if (!v) return t('请选择持续时长单位') }, })(v, meta) return res }, interval(v) { - if (!v) return '请选择告警周期' + if (!v) return t('请选择告警周期') }, interval_unit(v) { - if (!v) return '请选择告警周期' + if (!v) return t('请选择告警周期') }, topic(v) { - if (!v) return '请输入告警主题' + if (!v) return t('请输入告警主题') }, message(v) { - if (!v) return '请输入告警消息' + if (!v) return t('请输入告警消息') }, }) diff --git a/web/src/polaris/alert/types.ts b/web/src/polaris/alert/types.ts index 63e20582..43b993a2 100644 --- a/web/src/polaris/alert/types.ts +++ b/web/src/polaris/alert/types.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' export interface AlertInfo { id: string name: string @@ -44,9 +45,9 @@ export const AlterExprMap = { [AlterExprType.Ge]: '>=', [AlterExprType.Eq]: '==', [AlterExprType.Ne]: '!=', - [AlterExprType.Fluctuation]: '环比波动', - [AlterExprType.Rise]: '环比上升', - [AlterExprType.Decline]: '环比下降', + [AlterExprType.Fluctuation]: t('环比波动'), + [AlterExprType.Rise]: t('环比上升'), + [AlterExprType.Decline]: t('环比下降'), } export const AlterExprOptions = Object.entries(AlterExprMap).map(([key, value]) => { return { text: value, value: key } @@ -58,10 +59,10 @@ export enum AlertTimeInterval { day = 'd', } export const AlertTimeIntervalMap = { - [AlertTimeInterval.second]: '秒', - [AlertTimeInterval.minute]: '分钟', - [AlertTimeInterval.hour]: '小时', - [AlertTimeInterval.day]: '天', + [AlertTimeInterval.second]: t('秒'), + [AlertTimeInterval.minute]: t('分钟'), + [AlertTimeInterval.hour]: t('小时'), + [AlertTimeInterval.day]: t('天'), } export const AlertTimeIntervalOptions = Object.entries(AlertTimeIntervalMap).map(([key, value]) => { return { text: value, value: key } @@ -70,7 +71,7 @@ export enum MonitorType { Business = 'Business', } export const MonitorTypeMap = { - [MonitorType.Business]: '业务监控', + [MonitorType.Business]: t('业务监控'), } export const MonitorTypeOption = Object.entries(MonitorTypeMap).map(([key, value]) => { return { text: value, value: key } @@ -82,16 +83,16 @@ export enum MetricName { } export const MetricNameMap = { [MetricName.DiscoveryConnTotal]: { - text: '服务发现连接数', - unit: '个', + text: t('服务发现连接数'), + unit: t('个'), }, [MetricName.ConfigConnTotal]: { - text: '配置获取连接数', - unit: '个', + text: t('配置获取连接数'), + unit: t('个'), }, [MetricName.SdkClientTotal]: { - text: '客户端数', - unit: '个', + text: t('客户端数'), + unit: t('个'), }, } export const MetricNameOptions = Object.entries(MetricNameMap).map(([key, value]) => { @@ -99,37 +100,37 @@ export const MetricNameOptions = Object.entries(MetricNameMap).map(([key, value] }) export const IntervalOptions = [ { - text: '每1分钟告警一次', + text: t('每1分钟告警一次'), value: '1m', interval: 1, unit: AlertTimeInterval.minute, }, { - text: '每5分钟告警一次', + text: t('每5分钟告警一次'), value: '5m', interval: 5, unit: AlertTimeInterval.minute, }, { - text: '每15分钟告警一次', + text: t('每15分钟告警一次'), value: '15m', interval: 15, unit: AlertTimeInterval.minute, }, { - text: '每1小时告警一次', + text: t('每1小时告警一次'), value: '1h', interval: 1, unit: AlertTimeInterval.hour, }, { - text: '每4小时告警一次', + text: t('每4小时告警一次'), value: '4h', interval: 4, unit: AlertTimeInterval.hour, }, { - text: '每天告警一次', + text: t('每天告警一次'), value: '1d', interval: 1, unit: AlertTimeInterval.day, diff --git a/web/src/polaris/auth/common/UseableResource.tsx b/web/src/polaris/auth/common/UseableResource.tsx index d3f36af3..8ab88368 100644 --- a/web/src/polaris/auth/common/UseableResource.tsx +++ b/web/src/polaris/auth/common/UseableResource.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import * as React from 'react' import { purify } from 'saga-duck' import { Table, Justify, Segment, SearchBox } from 'tea-component' @@ -6,9 +8,9 @@ import { autotip } from 'tea-component/lib/table/addons' import { StrategyResourceEntry } from '../model' const ResourceOptions = [ - { text: '命名空间', value: 'namespaces' }, - { text: '服务', value: 'services' }, - { text: '配置分组', value: 'config_groups' }, + { text: t('命名空间'), value: 'namespaces' }, + { text: t('服务'), value: 'services' }, + { text: t('配置分组'), value: 'config_groups' }, ] interface Props { @@ -18,7 +20,7 @@ interface Props { configGroups: StrategyResourceEntry[] } } -export default purify(function (props: Props) { +export default purify(function(props: Props) { const { resources } = props const [filterResourceType, setFilterResourceType] = React.useState('namespaces') const [keyword, setKeyword] = React.useState('') @@ -45,16 +47,16 @@ export default purify(function (props: Props) { columns={[ { key: 'name', - header: '名称', + header: t('名称'), render: (x: any) => { if (x.name === '*') { if (filterResourceType === 'namespaces') { - return '所有命名空间' + return t('所有命名空间') } if (filterResourceType === 'service') { - return '所有服务' + return t('所有服务') } - return '所有配置分组' + return t('所有配置分组') } if (filterResourceType === 'namespaces') { return x.name @@ -67,9 +69,9 @@ export default purify(function (props: Props) { }, { key: 'auth', - header: '权限', + header: t('权限'), render: () => { - return '读|写' + return t('读|写') }, }, ]} diff --git a/web/src/polaris/auth/common/UseableResourceFetcher.ts b/web/src/polaris/auth/common/UseableResourceFetcher.ts index 039f9853..892edb0b 100644 --- a/web/src/polaris/auth/common/UseableResourceFetcher.ts +++ b/web/src/polaris/auth/common/UseableResourceFetcher.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import Fetcher from '@src/polaris/common/ducks/Fetcher' import { DescribePrincipalResourcesParams, describePrincipalResources, StrategyResourceEntry } from '../model' diff --git a/web/src/polaris/auth/constants.ts b/web/src/polaris/auth/constants.ts index e96fa4d6..62987b5b 100644 --- a/web/src/polaris/auth/constants.ts +++ b/web/src/polaris/auth/constants.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { AuthSubjectType } from './policy/Page' export enum TAB { @@ -17,10 +18,10 @@ export enum DescribeStrategyOption { Mix = '', } const TAB_LABLES_MAP = { - [TAB.USER]: '用户', - [TAB.USERGROUP]: '用户组', - [TAB.POLICY]: '权限策略', - [TAB.USEABLE_RESOURCE]: '可操作资源', + [TAB.USER]: t('用户'), + [TAB.USERGROUP]: t('用户组'), + [TAB.POLICY]: t('权限策略'), + [TAB.USEABLE_RESOURCE]: t('可操作资源'), } export const AuthTabs = Object.keys(TAB_LABLES_MAP).map(id => ({ id, diff --git a/web/src/polaris/auth/login/Page.tsx b/web/src/polaris/auth/login/Page.tsx index 5830a39d..fbcda06e 100644 --- a/web/src/polaris/auth/login/Page.tsx +++ b/web/src/polaris/auth/login/Page.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import * as React from 'react' import { purify, DuckCmpProps } from 'saga-duck' @@ -15,12 +17,12 @@ overflow:hidden; }`, ) -export default purify(function (props: DuckCmpProps) { +export default purify(function(props: DuckCmpProps) { const { duck, store, dispatch } = props const { ducks, creators, selector } = duck const { userName, password } = ducks.form.getAPI(store, dispatch).getFields(['userName', 'password']) const { preError } = selector(store) - const licenseToolTip = preError && 'License已超过最大过期时间' + const licenseToolTip = preError && t('License已超过最大过期时间') return (
) { > - 北极星服务治理中心 + 北极星服务治理中心 - 一个支持多语言、多框架和异构基础设施的服务治理中心,提供服务发现、流量调度、熔断降级、限流鉴权和可观测性等服务治理功能。北极星治理中心默认提供服务注册功能,也可以搭配其他服务注册中心使用。 + + 一个支持多语言、多框架和异构基础设施的服务治理中心,提供服务发现、流量调度、熔断降级、限流鉴权和可观测性等服务治理功能。北极星治理中心默认提供服务注册功能,也可以搭配其他服务注册中心使用。 + @@ -61,7 +65,7 @@ export default purify(function (props: DuckCmpProps) {

- 登录 + 登录

@@ -69,26 +73,27 @@ export default purify(function (props: DuckCmpProps) { - 外网访问建议设置访问控制策略 + 外网访问建议设置访问控制策略 - 初始用户名和密码为polaris/polaris + 初始用户名和密码为 + polaris/polaris - + - + { + onChange={v => { password.setValue(v) password.setTouched(true) password.setError('') @@ -116,7 +121,7 @@ export default purify(function (props: DuckCmpProps) { }} disabled={preError} > - 登录 + 登录 diff --git a/web/src/polaris/auth/login/PageDuck.ts b/web/src/polaris/auth/login/PageDuck.ts index c0dde857..b419ca28 100644 --- a/web/src/polaris/auth/login/PageDuck.ts +++ b/web/src/polaris/auth/login/PageDuck.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { select, put, call } from 'redux-saga/effects' import { takeLatest } from 'redux-saga-catch' import { createToPayload } from 'saga-duck' @@ -117,12 +118,12 @@ export class CreateFormDuck extends Form { window.localStorage.setItem(LoginRoleKey, loginResponse.role) window.localStorage.setItem(LoginUserIdKey, loginResponse.user_id) window.localStorage.setItem(LoginUserOwnerIdKey, loginResponse.owner_id) - window.location.hash = "/service" + window.location.hash = '/service' } else { throw new Error() } } catch (e) { - yield put(creators.markInvalid('password', '网络异常或用户名,密码错误')) + yield put(creators.markInvalid('password', t('网络异常或用户名,密码错误'))) throw e } } @@ -133,12 +134,12 @@ export class CreateFormDuck extends Form { const validator = CreateFormDuck.combineValidators({ userName(v) { if (!v) { - return '请输入用户名' + return t('请输入用户名') } }, password(v) { if (!v) { - return '请输入密码' + return t('请输入密码') } }, }) diff --git a/web/src/polaris/auth/model.ts b/web/src/polaris/auth/model.ts index dd2fc4b5..b04acfd6 100644 --- a/web/src/polaris/auth/model.ts +++ b/web/src/polaris/auth/model.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { apiRequest, getApiRequest, putApiRequest, SuccessCode, ApiResponse } from '../common/util/apiRequest' import { ttl, once } from '../common/helpers/cacheable' import router from '../common/util/router' diff --git a/web/src/polaris/auth/policy/Page.tsx b/web/src/polaris/auth/policy/Page.tsx index 934b86a1..6107196e 100644 --- a/web/src/polaris/auth/policy/Page.tsx +++ b/web/src/polaris/auth/policy/Page.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import * as React from 'react' import { DuckCmpProps, memorize } from 'saga-duck' import Duck from './PageDuck' @@ -39,20 +41,24 @@ export enum AuthResourceType { CONFIGURATION = 'config_groups', } export const AUTH_SUBJECT_TYPE_MAP = { - [AuthSubjectType.USER]: { text: '用户', urlKey: 'user' }, - [AuthSubjectType.USERGROUP]: { text: '用户组', urlKey: 'usergroup' }, + [AuthSubjectType.USER]: { text: t('用户'), urlKey: 'user' }, + [AuthSubjectType.USERGROUP]: { text: t('用户组'), urlKey: 'usergroup' }, } export const AUTH_RESOURCE_TYPE_MAP = { [AuthResourceType.NAMESPACE]: { - text: '命名空间', + text: t('命名空间'), columnsRender: x => x.name, }, [AuthResourceType.SERVICE]: { - text: '服务', - columnsRender: x => `${x.name}(${x.namespace})`, + text: t('服务'), + columnsRender: x => + t('{{attr0}}({{attr1}})', { + attr0: x.name, + attr1: x.namespace, + }), }, [AuthResourceType.CONFIGURATION]: { - text: '配置分组', + text: t('配置分组'), columnsRender: x => x.name, }, } @@ -74,11 +80,11 @@ insertCSS( const formatPolicyName = (name: string) => { let trimName = name - if (name.indexOf('(用户组)') === 0) { - trimName = name.replace('(用户组)', '') + if (name.indexOf(t('(用户组)')) === 0) { + trimName = name.replace(t('(用户组)'), '') } - if (name.indexOf('(用户)') === 0) { - trimName = name.replace('(用户)', '') + if (name.indexOf(t('(用户)')) === 0) { + trimName = name.replace(t('(用户)'), '') } return trimName } @@ -115,7 +121,7 @@ export default function AuthPage(props: DuckCmpProps) { currentAuthItem?.principals?.users?.length === 1 && currentAuthItem?.principals?.users?.[0]?.id === getOwnerUin() const renderListItem = (item: AuthStrategy) => { - const principalType = item.name.indexOf('用户组') > -1 ? AuthSubjectType.USERGROUP : AuthSubjectType.USER + const principalType = item.name.indexOf(t('用户组')) > -1 ? AuthSubjectType.USERGROUP : AuthSubjectType.USER const isActive = item.id === currentAuthItem.id const isOwnerDefaultPrinciple = item.default_strategy && @@ -141,7 +147,7 @@ export default function AuthPage(props: DuckCmpProps) { {formatPolicyName(item.name)} {item.default_strategy && ( - + {principalType === AuthSubjectType.USER ? ( ) { } appearance='pure'> handlers.modify(item.id)} disabled={isOwnerDefaultPrinciple}> - {'编辑'} + {t('编辑')} handlers.delete(item.id)} disabled={item.default_strategy}> - {'删除'} + {t('删除')} @@ -177,7 +183,7 @@ export default function AuthPage(props: DuckCmpProps) { <> {!isInDetailpage && isOwner() && ( )} @@ -204,7 +210,8 @@ export default function AuthPage(props: DuckCmpProps) { current={false} > - 默认策略({defaultList.length}) + 默认策略( + {defaultList.length}) {defaultList.filter(() => collapseDefault).map(renderListItem)} @@ -218,7 +225,8 @@ export default function AuthPage(props: DuckCmpProps) { current={false} > - 自定义策略({customList.length}) + 自定义策略( + {customList.length}) {customList.filter(() => collapseCustom).map(renderListItem)} @@ -238,14 +246,14 @@ export default function AuthPage(props: DuckCmpProps) { onClick={() => handlers.modify(currentAuthItem.id)} disabled={isCurrAuthItemOwnerDefaultPrinciple} > - {'编辑'} + {t('编辑')} ) @@ -253,15 +261,15 @@ export default function AuthPage(props: DuckCmpProps) { > - - {currentAuthItem.comment || '无备注'} + + {currentAuthItem.comment || t('无备注')}
{isInDetailpage ? ( - + ) { ) : ( <> - + ) { }) ) : ( - {'暂无对应授权对象'} + {t('暂无对应授权对象')} )} - + ) { {currentAuthItem.resources[showAuthResourceType].length === 1 && currentAuthItem.resources[showAuthResourceType][0].id === '*' ? (
- {`全部${AUTH_RESOURCE_TYPE_MAP[showAuthResourceType].text}(含后续新增)`} + {t('全部{{attr0}}(含后续新增)', { + attr0: AUTH_RESOURCE_TYPE_MAP[showAuthResourceType].text, + })}
) : ( ) { columns={[ { key: 'name', - header: '名称', + header: t('名称'), render: AUTH_RESOURCE_TYPE_MAP[showAuthResourceType].columnsRender, }, - { key: 'auth', header: '权限', render: () => '读|写' }, + { key: 'auth', header: t('权限'), render: () => t('读|写') }, ]} addons={[scrollable({ maxHeight: '300px' }), autotip({})]} style={{ marginTop: '20px' }} @@ -345,7 +355,7 @@ export default function AuthPage(props: DuckCmpProps) { )} ) : ( - + )} @@ -356,7 +366,7 @@ export default function AuthPage(props: DuckCmpProps) { return isInDetailpage ? ( contentElement ) : ( - }> + }> {contentElement} ) diff --git a/web/src/polaris/auth/policy/PageDuck.ts b/web/src/polaris/auth/policy/PageDuck.ts index 8a9bb1af..4c3f86c6 100644 --- a/web/src/polaris/auth/policy/PageDuck.ts +++ b/web/src/polaris/auth/policy/PageDuck.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { put, select } from 'redux-saga/effects' import { takeLatest } from 'redux-saga-catch' import { reduceFromPayload, createToPayload } from 'saga-duck' @@ -112,16 +113,16 @@ export default abstract class PolicyPageDuck extends PageDuck { yield takeLatest(types.DELETE, function*(action) { const id = action.payload const confirm = yield Modal.confirm({ - message: '确认删除如下策略?', - description: '删除后,策略不可用且无法恢复', + message: t('确认删除如下策略?'), + description: t('删除后,策略不可用且无法恢复'), }) if (confirm) { const result = yield deleteGovernanceStrategies([{ id }]) if (result) { - notification.success({ description: '删除成功' }) + notification.success({ description: t('删除成功') }) yield put(creators.reload()) } else { - notification.error({ description: '删除失败' }) + notification.error({ description: t('删除失败') }) } } }) diff --git a/web/src/polaris/auth/policy/operation/Create.tsx b/web/src/polaris/auth/policy/operation/Create.tsx index 07f370d0..bbe6a386 100644 --- a/web/src/polaris/auth/policy/operation/Create.tsx +++ b/web/src/polaris/auth/policy/operation/Create.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import * as React from 'react' import { purify, DuckCmpProps } from 'saga-duck' import { @@ -27,9 +29,9 @@ import { Namespace, Service } from '@src/polaris/service/types' import router from '@src/polaris/common/util/router' import { ConfigFileGroup } from '@src/polaris/configuration/fileGroup/types' const steps = [ - { id: '1', label: '选择用户' }, - { id: '2', label: '授权' }, - { id: '3', label: '预览' }, + { id: '1', label: t('选择用户') }, + { id: '2', label: t('授权') }, + { id: '3', label: t('预览') }, ] export default purify(function(props: DuckCmpProps) { @@ -59,7 +61,7 @@ export default purify(function(props: DuckCmpProps) { store={store} duck={duck} dispatch={dispatch} - title={composedId?.id ? '编辑策略' : '创建策略'} + title={composedId?.id ? t('编辑策略') : t('创建策略')} backRoute={'/policy'} > {/* 内容区域一般使用 Card 组件显示内容 */} @@ -67,13 +69,13 @@ export default purify(function(props: DuckCmpProps) { }> {step === '1' && (
- + {isModify ? {name.getValue()} : } - + - + {!originPolicy?.default_strategy || !isModify ? ( ) { > ) { ) { ) : ( - {'默认策略不可变更授权角色'} + {t('默认策略不可变更授权角色')} )} )} {step === '2' && (
- + ) { }} style={{ marginTop: '10px' }} > - {'全部命名空间(含后续新增)'} - {'指定命名空间'} + {t('全部命名空间(含后续新增)')} + {t('指定命名空间')} {!useAllNamespace.getValue() && ( ) { }} style={{ marginTop: '10px' }} > - {'全部服务(含后续新增)'} - {'指定服务'} + {t('全部服务(含后续新增)')} + {t('指定服务')} {!useAllService.getValue() && ( ) { }} style={{ marginTop: '10px' }} > - {'全部配置分组(含后续新增)'} - {'指定配置分组'} + {t('全部配置分组(含后续新增)')} + {t('指定配置分组')} {!useAllConfigGroup.getValue() && ( ) { - - {'读操作|写操作'} + + {t('读操作|写操作')} )} {step === '3' && (
- + {name.getValue()} - - {userSelection.map(item => `${item.name}(${item.id})`).join(',' || '无选中用户')} + + + {userSelection.map(item => `${item.name}(${item.id})`).join(',' || t('无选中用户'))} + - + - {userGroupSelection.map(item => `${item.name}(${item.id})`).join(',' || '无选中用户组')} + {userGroupSelection.map(item => `${item.name}(${item.id})`).join(',' || t('无选中用户组'))} - + ) { > {useAllNamespace.getValue() ? ( - {'全部命名空间(含后续新增)'} + {t('全部命名空间(含后续新增)')} ) : (
'读|写' }, + { key: 'auth', header: t('权限'), render: () => t('读|写') }, ]} addons={[autotip({})]} /> @@ -233,17 +237,17 @@ export default purify(function(props: DuckCmpProps) { {useAllService.getValue() ? ( - {'全部服务(含后续新增)'} + {t('全部服务(含后续新增)')} ) : (
'读|写' }, + { key: 'auth', header: t('权限'), render: () => t('读|写') }, ]} addons={[autotip({})]} /> @@ -251,17 +255,17 @@ export default purify(function(props: DuckCmpProps) { {useAllService.getValue() ? ( - {'全部服务(含后续新增)'} + {t('全部服务(含后续新增)')} ) : (
'读|写' }, + { key: 'auth', header: t('权限'), render: () => t('读|写') }, ]} addons={[autotip({})]} /> @@ -281,7 +285,7 @@ export default purify(function(props: DuckCmpProps) { }} style={{ marginRight: '15px' }} > - {'完成'} + {t('完成')} )} {Number(step) < 3 && ( @@ -292,7 +296,7 @@ export default purify(function(props: DuckCmpProps) { }} style={{ marginRight: '15px' }} > - {'下一步'} + {t('下一步')} )} {Number(step) > 1 && ( @@ -303,7 +307,7 @@ export default purify(function(props: DuckCmpProps) { }} style={{ marginRight: '15px' }} > - {'上一步'} + {t('上一步')} )} diff --git a/web/src/polaris/auth/policy/operation/CreateDuck.ts b/web/src/polaris/auth/policy/operation/CreateDuck.ts index 714debe4..dd9ceded 100644 --- a/web/src/polaris/auth/policy/operation/CreateDuck.ts +++ b/web/src/polaris/auth/policy/operation/CreateDuck.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { select, put } from 'redux-saga/effects' import { takeLatest } from 'redux-saga-catch' import { reduceFromPayload, createToPayload } from 'saga-duck' @@ -199,10 +200,10 @@ export default abstract class CreateDuck extends DetailPage { }, ] as any) if (result) { - notification.success({ description: '编辑成功' }) + notification.success({ description: t('编辑成功') }) router.navigate(`/policy?authTab=policy`) } else { - notification.error({ description: '编辑失败' }) + notification.error({ description: t('编辑失败') }) } } else { const result = yield createGovernanceStrategy({ @@ -223,10 +224,10 @@ export default abstract class CreateDuck extends DetailPage { comment: values.comment, }) if (result) { - notification.success({ description: '创建成功' }) + notification.success({ description: t('创建成功') }) router.navigate(`/policy?authTab=policy`) } else { - notification.error({ description: '创建失败' }) + notification.error({ description: t('创建失败') }) } } }) @@ -334,13 +335,13 @@ const validator = CreateFormDuck.combineValidators({ return } if (!v) { - return '请输入名称' + return t('请输入名称') } if (!v.match(/^[\u4E00-\u9FA5A-Za-z0-9_\\-]+$/)) { - return '只能使用中文、数字、大小写字母 以及- _组成' + return t('只能使用中文、数字、大小写字母 以及- _组成') } if (v.length > 64) { - return '最大长度为64' + return t('最大长度为64') } }, }) diff --git a/web/src/polaris/auth/user/Page.tsx b/web/src/polaris/auth/user/Page.tsx index 1793c246..0bd5f5ab 100644 --- a/web/src/polaris/auth/user/Page.tsx +++ b/web/src/polaris/auth/user/Page.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { DuckCmpProps, memorize } from 'saga-duck' import Duck from './PageDuck' @@ -41,12 +43,12 @@ export default function ServicePage(props: DuckCmpProps) { <> {!isInDetailpage && isOwner() && ( )} {isInDetailpage && isOwner() && ( )} @@ -82,7 +84,7 @@ export default function ServicePage(props: DuckCmpProps) { return isInDetailpage ? ( contentElement ) : ( - }> + }> {contentElement} ) diff --git a/web/src/polaris/auth/user/PageDuck.tsx b/web/src/polaris/auth/user/PageDuck.tsx index 8d5048c3..c85c8b45 100644 --- a/web/src/polaris/auth/user/PageDuck.tsx +++ b/web/src/polaris/auth/user/PageDuck.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import { takeLatest } from 'redux-saga-catch' import { User, @@ -123,20 +125,20 @@ export default class PageDuck extends GridPageDuck { yield takeLatest(types.DELETE, function*(action) { const users = action.payload const confirm = yield Modal.confirm({ - message: '确认删除用户?', + message: t('确认删除用户?'), description: ( <> - {'删除后,用户不可用且无法恢复'} + {t('删除后,用户不可用且无法恢复')} ), }) if (confirm) { const result = yield deleteGovernanceUsers(users.map(item => ({ id: item.id }))) if (result) { - notification.success({ description: '删除成功' }) + notification.success({ description: t('删除成功') }) yield put(creators.reload()) } else { - notification.error({ description: '删除失败' }) + notification.error({ description: t('删除失败') }) } } }) @@ -186,7 +188,7 @@ export default class PageDuck extends GridPageDuck { }), ) if (result) { - notification.success({ description: '编辑成功' }) + notification.success({ description: t('编辑成功') }) yield put(creators.reload()) } }) @@ -212,7 +214,7 @@ export default class PageDuck extends GridPageDuck { }), ) if (result) { - notification.success({ description: '编辑成功' }) + notification.success({ description: t('编辑成功') }) yield put(creators.reload()) } }) @@ -239,7 +241,7 @@ export default class PageDuck extends GridPageDuck { }), ) if (result) { - notification.success({ description: '编辑成功' }) + notification.success({ description: t('编辑成功') }) yield put(creators.reload()) } }) @@ -251,7 +253,9 @@ export default class PageDuck extends GridPageDuck { } = yield describeGovernanceUserToken({ id }) const { destroy } = Modal.show({ size: 'xl', - caption: `查看${name}的token`, + caption: t('查看{{attr0}}的token', { + attr0: name, + }), children: , onClose: () => destroy(), }) diff --git a/web/src/polaris/auth/user/detail/Page.tsx b/web/src/polaris/auth/user/detail/Page.tsx index e90a157d..7b15d6ed 100644 --- a/web/src/polaris/auth/user/detail/Page.tsx +++ b/web/src/polaris/auth/user/detail/Page.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import * as React from 'react' import { purify, DuckCmpProps } from 'saga-duck' import { Card, Form, Text, FormItem, Table, Button, FormText, Tabs, TabPanel } from 'tea-component' @@ -26,13 +28,15 @@ export default purify(function(props: DuckCmpProps) { store={store} duck={duck} dispatch={dispatch} - title={`用户详情(${composedId?.id})`} + title={t('用户详情({{attr0}})', { + attr0: composedId?.id, + })} backRoute={'/user'} > {/* 内容区域一般使用 Card 组件显示内容 */} } > - + {data?.name} - + {composedId?.id} - + {comment || '-'}{' '} - + {mobile || '-'} - + {email || '-'} @@ -112,26 +116,26 @@ export default purify(function(props: DuckCmpProps) { }, { key: 'token_enable', - header: '状态', + header: t('状态'), render: x => x.token_enable ? ( - {'生效中'} + {t('生效中')} ) : ( - {'已失效'} + {t('已失效')} ), }, { key: 'operation', - header: '操作', + header: t('操作'), render: x => ( <> {getOwnerUin().toString() !== x.id && isOwner() && ( )} ), @@ -139,7 +143,7 @@ export default purify(function(props: DuckCmpProps) { ]} >
) : ( - {'仅主账号可查看Token'} + {t('仅主账号可查看Token')} )} diff --git a/web/src/polaris/auth/user/detail/PageDuck.ts b/web/src/polaris/auth/user/detail/PageDuck.ts index 9ba643c0..acc0a629 100644 --- a/web/src/polaris/auth/user/detail/PageDuck.ts +++ b/web/src/polaris/auth/user/detail/PageDuck.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { reduceFromPayload, createToPayload } from 'saga-duck' import DetailPage from '@src/polaris/common/ducks/DetailPage' import { @@ -120,10 +121,10 @@ export default abstract class CreateDuck extends DetailPage { const data = selectors.data(yield select()) const result = yield ModifyCommentDuck.show({ comment: data.comment, id }) if (result) { - notification.success({ description: '修改成功' }) + notification.success({ description: t('修改成功') }) yield put(creators.reload()) } else { - notification.error({ description: '修改失败' }) + notification.error({ description: t('修改失败') }) } }) yield takeLatest(types.MODIFY, function*() { @@ -176,11 +177,19 @@ export default abstract class CreateDuck extends DetailPage { } = selector(yield select()) const result = yield modifyGovernanceUserToken({ id, token_enable: !token_enable }) if (result) { - notification.success({ description: `${token_enable ? '禁用' : '启用'}成功` }) + notification.success({ + description: t('{{attr0}}成功', { + attr0: token_enable ? t('禁用') : t('启用'), + }), + }) yield delay(3000) // token refresh has a delay yield put(creators.reload()) } else { - notification.error({ description: `${token_enable ? '禁用' : '启用'}失败` }) + notification.error({ + description: t('{{attr0}}失败', { + attr0: token_enable ? t('禁用') : t('启用'), + }), + }) } }) yield takeLatest(types.RESET_TOKEN, function*() { @@ -188,15 +197,15 @@ export default abstract class CreateDuck extends DetailPage { const result = yield resetGovernanceUserToken({ id }) if (result) { - notification.success({ description: '重置成功' }) + notification.success({ description: t('重置成功') }) if (id === getUin()) { - notification.warning({ description: '您已成功重置Token,请重新登录。' }) + notification.warning({ description: t('您已成功重置Token,请重新登录。') }) yield delay(3000) userLogout() } yield put(creators.reload()) } else { - notification.error({ description: '重置失败' }) + notification.error({ description: t('重置失败') }) } }) } diff --git a/web/src/polaris/auth/user/getColumns.tsx b/web/src/polaris/auth/user/getColumns.tsx index 7ac56635..5b4b405e 100644 --- a/web/src/polaris/auth/user/getColumns.tsx +++ b/web/src/polaris/auth/user/getColumns.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import * as React from 'react' import { DuckCmpProps } from 'saga-duck' import Duck, { UserItem } from './PageDuck' @@ -9,19 +11,19 @@ export default ({ duck: { creators }, dispatch }: DuckCmpProps): Column { const canRead = isOwner() || getUin().toString() === x.id return canRead ? ( {x.name} - {getUin().toString() === x.id && '(当前登录)'} + {getUin().toString() === x.id && t('(当前登录)')} ) : ( - {x.name} {getUin().toString() === x.id && '(当前登录)'} + {x.name} {getUin().toString() === x.id && t('(当前登录)')} ) }, @@ -29,27 +31,27 @@ export default ({ duck: { creators }, dispatch }: DuckCmpProps): Column {getOwnerUin().toString() === x.id ? '主账号' : '子账号'}, + header: t('用户类型'), + render: x => {getOwnerUin().toString() === x.id ? t('主账号') : t('子账号')}, }, { key: 'id', - header: '用户id', + header: t('用户id'), render: x => {x.id}, }, { key: 'createTime', - header: '创建时间', + header: t('创建时间'), render: x => {x.ctime}, }, { key: 'operation', - header: '操作', + header: t('操作'), render: x => ( <> {isOwner() && ( )} {isOwner() && ( - + dispatch(creators.attach(x))}> - {'关联用户组'} + {t('关联用户组')} dispatch(creators.delete([x]))} disabled={getOwnerUin().toString() === x.id}> - {'删除'} + {t('删除')} diff --git a/web/src/polaris/auth/user/operation/AttachUserGroup.tsx b/web/src/polaris/auth/user/operation/AttachUserGroup.tsx index 71de5802..20bf89a3 100644 --- a/web/src/polaris/auth/user/operation/AttachUserGroup.tsx +++ b/web/src/polaris/auth/user/operation/AttachUserGroup.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import * as React from 'react' import { purify, DuckCmpProps } from 'saga-duck' import Duck from './AttachUserGroupDuck' @@ -15,15 +17,15 @@ export default purify(function(props: DuckCmpProps) { duck={duck} store={store} dispatch={dispatch} - title={'关联用户组'} + title={t('关联用户组')} size={'l'} - defaultSubmitText={'确定'} - defaultCancelText={'取消'} + defaultSubmitText={t('确定')} + defaultCancelText={t('取消')} >
- + ) { duck={duck} store={store} dispatch={dispatch} - title={'授权'} + title={t('授权')} size={'l'} - defaultSubmitText={'授权'} - defaultCancelText={'取消'} + defaultSubmitText={t('授权')} + defaultCancelText={t('取消')} > @@ -27,9 +29,9 @@ export default purify(function(props: DuckCmpProps) { {options?.name || '-'}({options?.id || '-'}) - + item.id), ) if (addArray.length <= 0 && removeArray.length <= 0) { - notification.warning({ description: '未做改动' }) - throw '未做改动' + notification.warning({ description: t('未做改动') }) + throw t('未做改动') } const principleName = authSubjectType === AuthSubjectType.USER ? 'users' : 'groups' const res = yield* resolvePromise( diff --git a/web/src/polaris/auth/user/operation/CreateUser.tsx b/web/src/polaris/auth/user/operation/CreateUser.tsx index c67790d1..514a0ea0 100644 --- a/web/src/polaris/auth/user/operation/CreateUser.tsx +++ b/web/src/polaris/auth/user/operation/CreateUser.tsx @@ -1,3 +1,4 @@ +import { t } from 'i18next' import * as React from 'react' import { purify, DuckCmpProps } from 'saga-duck' import Duck from './CreateUserDuck' @@ -6,7 +7,7 @@ import Dialog from '@src/polaris/common/duckComponents/Dialog' import FormField from '@src/polaris/common/duckComponents/form/Field' import Input from '@src/polaris/common/duckComponents/form/Input' import { isOwner } from '@src/polaris/common/util/common' -export const passwordRuleText = '请输入6至17位的密码' +export const passwordRuleText = t('请输入6至17位的密码') export default purify(function(props: DuckCmpProps) { const { duck, store, dispatch } = props const { ducks, selector } = duck @@ -19,10 +20,10 @@ export default purify(function(props: DuckCmpProps) { duck={duck} store={store} dispatch={dispatch} - title={options?.isModify ? (options?.isModifyPassword ? '修改密码' : '编辑用户') : '新建用户'} + title={options?.isModify ? (options?.isModifyPassword ? t('修改密码') : t('编辑用户')) : t('新建用户')} size={'s'} - defaultSubmitText={'确定'} - defaultCancelText={'取消'} + defaultSubmitText={t('确定')} + defaultCancelText={t('取消')} > {options?.isModify ? ( @@ -31,48 +32,48 @@ export default purify(function(props: DuckCmpProps) { {!isOwner() && ( )} - + - + ) : ( <> - + - + ) ) : ( <> - + - + - + - + - + - + diff --git a/web/src/polaris/auth/user/operation/CreateUserDuck.ts b/web/src/polaris/auth/user/operation/CreateUserDuck.ts index 01c02d9c..e8125637 100644 --- a/web/src/polaris/auth/user/operation/CreateUserDuck.ts +++ b/web/src/polaris/auth/user/operation/CreateUserDuck.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { put, select } from 'redux-saga/effects' import { createGovernanceUsers, modifyGovernanceUserPassword, modifyGovernanceUser } from '../../model' import FormDialog from '@src/polaris/common/ducks/FormDialog' @@ -47,14 +48,14 @@ export default class CreateUserDuck extends FormDialog { new_password, }) if (result) { - notification.success({ description: '修改密码成功' }) + notification.success({ description: t('修改密码成功') }) if (id === getUin()) { - notification.warning({ description: '您已成功重置密码,请重新登录。' }) + notification.warning({ description: t('您已成功重置密码,请重新登录。') }) yield delay(3000) userLogout() } } else { - notification.error({ description: '修改密码失败' }) + notification.error({ description: t('修改密码失败') }) } } else { result = yield modifyGovernanceUser({ @@ -63,9 +64,9 @@ export default class CreateUserDuck extends FormDialog { email, }) if (result) { - notification.success({ description: '编辑成功' }) + notification.success({ description: t('编辑成功') }) } else { - notification.error({ description: '编辑失败' }) + notification.error({ description: t('编辑失败') }) } } return result @@ -81,9 +82,9 @@ export default class CreateUserDuck extends FormDialog { }, ]) if (result) { - notification.success({ description: '创建成功' }) + notification.success({ description: t('创建成功') }) } else { - notification.error({ description: '创建失败' }) + notification.error({ description: t('创建失败') }) } return result } @@ -139,13 +140,13 @@ const validator = CreateForm.combineValidators({ return } if (!v) { - return '请输入名称' + return t('请输入名称') } if (!v.match(/^[\u4E00-\u9FA5A-Za-z0-9_\\-]+$/)) { - return '只能使用中文、数字、大小写字母 以及- _组成' + return t('只能使用中文、数字、大小写字母 以及- _组成') } if (v.length > 64) { - return '最大长度为64' + return t('最大长度为64') } }, password(v, values) { @@ -153,7 +154,7 @@ const validator = CreateForm.combineValidators({ return } if (!v) { - return '请输入密码' + return t('请输入密码') } if (v.length < 6 || v.length > 17) { return passwordRuleText @@ -167,7 +168,7 @@ const validator = CreateForm.combineValidators({ return } if (!v && values.id) { - return '请输入旧密码' + return t('请输入旧密码') } }, new_password(v, values, meta) { @@ -175,7 +176,7 @@ const validator = CreateForm.combineValidators({ return } if (!v && values.id) { - return '请输入新密码' + return t('请输入新密码') } if (v.length < 6 || v.length > 17) { return passwordRuleText @@ -184,13 +185,13 @@ const validator = CreateForm.combineValidators({ confirmPassword(v, values, meta) { if (meta.isModifyPassword || !meta.isModify) { if (!v) { - return '请确认密码' + return t('请确认密码') } if (meta.isModify && values.new_password !== v) { - return '两次输入密码不一致' + return t('两次输入密码不一致') } if (!meta.isModify && values.password !== v) { - return '两次输入密码不一致' + return t('两次输入密码不一致') } } }, diff --git a/web/src/polaris/auth/user/operation/ModifyComment.tsx b/web/src/polaris/auth/user/operation/ModifyComment.tsx index 96838fda..ea42c53b 100644 --- a/web/src/polaris/auth/user/operation/ModifyComment.tsx +++ b/web/src/polaris/auth/user/operation/ModifyComment.tsx @@ -1,3 +1,4 @@ +import { t } from 'i18next' import * as React from 'react' import { purify, DuckCmpProps } from 'saga-duck' import Duck from './ModifyCommentDuck' @@ -17,14 +18,14 @@ export default purify(function(props: DuckCmpProps) { duck={duck} store={store} dispatch={dispatch} - title={'修改备注'} + title={t('修改备注')} size={300} - defaultSubmitText={'确定'} - defaultCancelText={'取消'} + defaultSubmitText={t('确定')} + defaultCancelText={t('取消')} > - - + +
diff --git a/web/src/polaris/auth/user/operation/ResourcePrincipalAuth.tsx b/web/src/polaris/auth/user/operation/ResourcePrincipalAuth.tsx index 17402bd4..92ab9d55 100644 --- a/web/src/polaris/auth/user/operation/ResourcePrincipalAuth.tsx +++ b/web/src/polaris/auth/user/operation/ResourcePrincipalAuth.tsx @@ -1,3 +1,4 @@ +import { t } from 'i18next' import React from 'react' import { Text, Tabs, Alert, TabPanel } from 'tea-component' import { AuthSubjectTabs, AuthSubjectType } from '../../policy/Page' @@ -21,11 +22,11 @@ export default function ResourcePrincipalAuth(props: Props & DuckCmpProps) onActive={tab => setShowAuthSubjectType(tab.id as AuthSubjectType)} > - {'授予权限的用户或者用户组,具有该命名空间的读写权限,所有用户具有读权限'} + {t('授予权限的用户或者用户组,具有该命名空间的读写权限,所有用户具有读权限')} ) ) /> - {'支持按住shift进行多选'} + {t('支持按住shift进行多选')}
) diff --git a/web/src/polaris/auth/user/operation/ShowToken.tsx b/web/src/polaris/auth/user/operation/ShowToken.tsx index f75780ae..41bffeed 100644 --- a/web/src/polaris/auth/user/operation/ShowToken.tsx +++ b/web/src/polaris/auth/user/operation/ShowToken.tsx @@ -1,3 +1,4 @@ +import { t } from 'i18next' import React from 'react' import { Form, FormItem, Button, FormText, Text } from 'tea-component' import CopyableText from '@src/polaris/common/components/CopyableText' @@ -9,7 +10,7 @@ export default function ShowToken(props: { token: string; name: string }) { return (
- + {name} ) { <> {!isInDetailpage && isOwner() && ( )} {isInDetailpage && isOwner() && ( )} @@ -68,7 +69,7 @@ export default function ServicePage(props: DuckCmpProps) { return isInDetailpage ? ( contentElement ) : ( - }> + }> {contentElement} ) diff --git a/web/src/polaris/auth/userGroup/PageDuck.tsx b/web/src/polaris/auth/userGroup/PageDuck.tsx index ae691e5c..b5c42939 100644 --- a/web/src/polaris/auth/userGroup/PageDuck.tsx +++ b/web/src/polaris/auth/userGroup/PageDuck.tsx @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { takeLatest } from 'redux-saga-catch' import { describeGovernanceGroups, @@ -164,27 +165,27 @@ export default class PageDuck extends GridPageDuck { }), ) if (result) { - notification.success({ description: '关联成功' }) + notification.success({ description: t('关联成功') }) yield put(creators.reload()) } }) yield takeLatest(types.DELETE, function*(action) { const group = action.payload as UserGroup const confirm = yield Modal.confirm({ - message: '确认删除用户组?', + message: t('确认删除用户组?'), description: ( <> - {'删除后,用户组不可用且无法恢复'} + {t('删除后,用户组不可用且无法恢复')} ), }) if (confirm) { const result = yield deleteGovernanceGroups([{ id: group.id }]) if (result) { - notification.success({ description: '删除成功' }) + notification.success({ description: t('删除成功') }) yield put(creators.reload()) } else { - notification.error({ description: '删除失败' }) + notification.error({ description: t('删除失败') }) } } }) @@ -211,7 +212,7 @@ export default class PageDuck extends GridPageDuck { }), ) if (result) { - notification.success({ description: '编辑成功' }) + notification.success({ description: t('编辑成功') }) yield put(creators.reload()) } }) @@ -236,7 +237,7 @@ export default class PageDuck extends GridPageDuck { }), ) if (result) { - notification.success({ description: '编辑成功' }) + notification.success({ description: t('编辑成功') }) yield put(creators.reload()) } }) @@ -247,7 +248,9 @@ export default class PageDuck extends GridPageDuck { } = yield describeGovernanceGroupToken({ id }) const { destroy } = Modal.show({ size: 'xl', - caption: `查看${name}的token`, + caption: t('查看{{attr0}}的token', { + attr0: name, + }), children: , onClose: () => destroy(), }) diff --git a/web/src/polaris/auth/userGroup/detail/Page.tsx b/web/src/polaris/auth/userGroup/detail/Page.tsx index df066bab..715b40b4 100644 --- a/web/src/polaris/auth/userGroup/detail/Page.tsx +++ b/web/src/polaris/auth/userGroup/detail/Page.tsx @@ -1,3 +1,4 @@ +import { t } from 'i18next' import * as React from 'react' import { purify, DuckCmpProps } from 'saga-duck' import { Card, Form, Text, FormItem, Table, Button, FormText, Tabs, TabPanel } from 'tea-component' @@ -28,19 +29,21 @@ export default purify(function(props: DuckCmpProps) { store={store} duck={duck} dispatch={dispatch} - title={`用户组详情(${data?.name})`} + title={t('用户组详情({{attr0}})', { + attr0: data?.name, + })} backRoute={'/usergroup'} > - + {data?.name} - + {composedId?.id} - + {comment || '-'} ), diff --git a/web/src/polaris/auth/userGroup/detail/PageDuck.ts b/web/src/polaris/auth/userGroup/detail/PageDuck.ts index ca4473af..1deab68f 100644 --- a/web/src/polaris/auth/userGroup/detail/PageDuck.ts +++ b/web/src/polaris/auth/userGroup/detail/PageDuck.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { reduceFromPayload, createToPayload } from 'saga-duck' import DetailPage from '@src/polaris/common/ducks/DetailPage' import { @@ -108,10 +109,10 @@ export default abstract class CreateDuck extends DetailPage { const data = selectors.data(yield select()) const result = yield IModifyCommentDuck.show({ comment: data.comment, instanceId, regionId, id }) if (result) { - notification.success({ description: '修改成功' }) + notification.success({ description: t('修改成功') }) yield put(creators.reload()) } else { - notification.error({ description: '修改失败' }) + notification.error({ description: t('修改失败') }) } }) yield takeLatest(types.TOGGLE_TOKEN, function*() { @@ -121,11 +122,19 @@ export default abstract class CreateDuck extends DetailPage { } = selector(yield select()) const result = yield modifyGovernanceGroupToken({ id, token_enable: !token_enable }) if (result) { - notification.success({ description: `${token_enable ? '禁用' : '启用'}成功` }) + notification.success({ + description: t('{{attr0}}成功', { + attr0: token_enable ? t('禁用') : t('启用'), + }), + }) yield delay(3000) // token refresh has a delay yield put(creators.reload()) } else { - notification.error({ description: `${token_enable ? '禁用' : '启用'}失败` }) + notification.error({ + description: t('{{attr0}}失败', { + attr0: token_enable ? t('禁用') : t('启用'), + }), + }) } }) yield takeLatest(types.RESET_TOKEN, function*() { @@ -133,10 +142,10 @@ export default abstract class CreateDuck extends DetailPage { const result = yield resetGovernanceGroupToken({ id }) if (result) { - notification.success({ description: '重置成功' }) + notification.success({ description: t('重置成功') }) yield put(creators.reload()) } else { - notification.error({ description: '重置失败' }) + notification.error({ description: t('重置失败') }) } }) } diff --git a/web/src/polaris/auth/userGroup/getColumns.tsx b/web/src/polaris/auth/userGroup/getColumns.tsx index 57f71609..e25fe103 100644 --- a/web/src/polaris/auth/userGroup/getColumns.tsx +++ b/web/src/polaris/auth/userGroup/getColumns.tsx @@ -1,3 +1,4 @@ +import { t } from 'i18next' import * as React from 'react' import { DuckCmpProps } from 'saga-duck' import Duck from './PageDuck' @@ -13,7 +14,7 @@ export default ({ duck: { creators, selector }, store, dispatch }: DuckCmpProps< return [ { key: 'name', - header: '用户组名称', + header: t('用户组名称'), render: x => ( {x.name} @@ -23,17 +24,17 @@ export default ({ duck: { creators, selector }, store, dispatch }: DuckCmpProps< }, { key: 'userCount', - header: '用户数量', + header: t('用户数量'), render: x => {x.user_count}, }, { key: 'comment', - header: '备注', + header: t('备注'), render: x => {x.comment}, }, { key: 'createTime', - header: '创建时间', + header: t('创建时间'), render: x => {x.ctime}, }, ...(isInDetailpage @@ -41,24 +42,24 @@ export default ({ duck: { creators, selector }, store, dispatch }: DuckCmpProps< : [ { key: 'operation', - header: '操作', + header: t('操作'), render: x => ( <> {isOwner() && ( )} {isOwner() && ( - + dispatch(creators.auth(x))}> - {'授权'} + {t('授权')} - dispatch(creators.delete(x))}>{'删除'} + dispatch(creators.delete(x))}>{t('删除')} )} diff --git a/web/src/polaris/auth/userGroup/operation/Create.tsx b/web/src/polaris/auth/userGroup/operation/Create.tsx index 85792a17..31229dbf 100644 --- a/web/src/polaris/auth/userGroup/operation/Create.tsx +++ b/web/src/polaris/auth/userGroup/operation/Create.tsx @@ -1,3 +1,4 @@ +import { t } from 'i18next' import * as React from 'react' import { purify, DuckCmpProps } from 'saga-duck' import Duck from './CreateDuck' @@ -19,22 +20,22 @@ export default purify(function(props: DuckCmpProps) { duck={duck} store={store} dispatch={dispatch} - title={options?.isModify ? '编辑用户组' : '新建用户组'} + title={options?.isModify ? t('编辑用户组') : t('新建用户组')} size={'l'} - defaultSubmitText={'确定'} - defaultCancelText={'取消'} + defaultSubmitText={t('确定')} + defaultCancelText={t('取消')} > - + {options?.isModify ? ( {name.getValue()} ) : ( )} - + ) { )} /> - + diff --git a/web/src/polaris/auth/userGroup/operation/CreateDuck.ts b/web/src/polaris/auth/userGroup/operation/CreateDuck.ts index 80ad6f11..ebe9fe34 100644 --- a/web/src/polaris/auth/userGroup/operation/CreateDuck.ts +++ b/web/src/polaris/auth/userGroup/operation/CreateDuck.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { put, select } from 'redux-saga/effects' import { describeGovernanceUsers, createGovernanceGroup, modifyGovernanceGroup, User } from '../../model' import { UserItem } from '../../user/PageDuck' @@ -56,9 +57,9 @@ export default class CreateDuck extends FormDialog { }, ]) if (result) { - notification.success({ description: '编辑成功' }) + notification.success({ description: t('编辑成功') }) } else { - notification.error({ description: '编辑失败' }) + notification.error({ description: t('编辑失败') }) } return result } else { @@ -68,9 +69,9 @@ export default class CreateDuck extends FormDialog { relation: { users: selection.map(item => ({ id: item.id })) }, }) if (result) { - notification.success({ description: '创建成功' }) + notification.success({ description: t('创建成功') }) } else { - notification.error({ description: '创建失败' }) + notification.error({ description: t('创建失败') }) } return result } @@ -120,13 +121,13 @@ class CreateForm extends Form { const validator = CreateForm.combineValidators({ name(v) { if (!v) { - return '请输入名称' + return t('请输入名称') } if (!v.match(/^[\u4E00-\u9FA5A-Za-z0-9_\\-]+$/)) { - return '只能使用中文、数字、大小写字母 以及- _组成' + return t('只能使用中文、数字、大小写字母 以及- _组成') } if (v.length > 64) { - return '最大长度为64' + return t('最大长度为64') } }, }) diff --git a/web/src/polaris/common/components/BaseLayout.tsx b/web/src/polaris/common/components/BaseLayout.tsx index a0ce3580..8181e76c 100644 --- a/web/src/polaris/common/components/BaseLayout.tsx +++ b/web/src/polaris/common/components/BaseLayout.tsx @@ -1,61 +1,50 @@ -import * as React from "react"; -import { Layout, Card, Blank, LoadingTip } from "tea-component"; +import { t } from 'i18next' +import * as React from 'react' +import { Layout, Card, Blank, LoadingTip } from 'tea-component' -const { Body, Content } = Layout; +const { Body, Content } = Layout type BasicPageProps = { - type?: "page" | "fregment"; - title?: React.ReactNode; - header?: React.ReactNode; - headerRender?: React.ReactNode; - more?: React.ReactNode; - operation?: React.ReactNode; - hideTitle?: boolean; - showBackButton?: boolean; - full?: boolean; - store: any; + type?: 'page' | 'fregment' + title?: React.ReactNode + header?: React.ReactNode + headerRender?: React.ReactNode + more?: React.ReactNode + operation?: React.ReactNode + hideTitle?: boolean + showBackButton?: boolean + full?: boolean + store: any selectors: { - ready: (store) => boolean; - loading?: (store) => boolean; - }; -}; + ready: (store) => boolean + loading?: (store) => boolean + } +} -export default class BasicLayout extends React.Component< - BasicPageProps, - Readonly<{}> -> { +export default class BasicLayout extends React.Component> { render() { - const ready = this.props.selectors.ready(this.props.store); - if (ready === null) return
diff --git a/web/src/polaris/configuration/fileGroup/detail/file/PageDuck.tsx b/web/src/polaris/configuration/fileGroup/detail/file/PageDuck.tsx index eff175e1..3c6f4d37 100644 --- a/web/src/polaris/configuration/fileGroup/detail/file/PageDuck.tsx +++ b/web/src/polaris/configuration/fileGroup/detail/file/PageDuck.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import Base from '@src/polaris/common/ducks/Page' import CreateDuck from './operation/CreateDuck' import { select, put } from 'redux-saga/effects' @@ -290,17 +292,17 @@ export default class PageDuck extends Base { yield takeLatest(types.DELETE, function*(action) { const { namespace, group } = selectors.composedId(yield select()) const confirm = yield Modal.confirm({ - message: '确认删除配置文件?', - description: '删除后,无法恢复。', + message: t('确认删除配置文件?'), + description: t('删除后,无法恢复。'), }) if (confirm) { const deleteId = action.payload const result = yield deleteConfigFiles({ namespace, group, name: deleteId }) if (result) { - notification.success({ description: '删除成功' }) + notification.success({ description: t('删除成功') }) yield put({ type: types.FETCH_DATA }) } else { - notification.error({ description: '删除失败' }) + notification.error({ description: t('删除失败') }) } } }) @@ -356,8 +358,8 @@ export default class PageDuck extends Base { const nextNode = fileMap[action.payload] if (editing && currentNode.name !== nextNode.name) { const confirm = yield Modal.confirm({ - message: '确认切换展示节点?', - description: '编辑未发布,现在切换将丢失已编辑内容', + message: t('确认切换展示节点?'), + description: t('编辑未发布,现在切换将丢失已编辑内容'), }) if (!confirm) return } @@ -386,7 +388,7 @@ export default class PageDuck extends Base { if (lastRelease) { const confirm = yield Modal.confirm({ size: 'xl', - caption: '内容对比', + caption: t('内容对比'), description: , } as any) if (!confirm) { @@ -395,11 +397,11 @@ export default class PageDuck extends Base { } const result = yield releaseConfigFile({ namespace, group, fileName: name, name }) if (result) { - notification.success({ description: '发布成功' }) + notification.success({ description: t('发布成功') }) yield put({ type: types.FETCH_DATA }) yield put({ type: types.SET_EDITING, payload: false }) } else { - notification.error({ description: '发布失败' }) + notification.error({ description: t('发布失败') }) } }) yield takeLatest(types.SAVE_CURRENT_NODE, function*() { @@ -416,11 +418,11 @@ export default class PageDuck extends Base { name: currentNode.name, }) if (result) { - notification.success({ description: '保存成功' }) + notification.success({ description: t('保存成功') }) yield put({ type: types.FETCH_DATA }) yield put({ type: types.SET_EDITING, payload: false }) } else { - notification.error({ description: '保存失败' }) + notification.error({ description: t('保存失败') }) } }) } diff --git a/web/src/polaris/configuration/fileGroup/detail/file/constants.ts b/web/src/polaris/configuration/fileGroup/detail/file/constants.ts index 7d8800a4..9e83d25e 100644 --- a/web/src/polaris/configuration/fileGroup/detail/file/constants.ts +++ b/web/src/polaris/configuration/fileGroup/detail/file/constants.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' export enum FileStatus { Success = 'success', Fail = 'failure', @@ -5,15 +6,15 @@ export enum FileStatus { } export const FileStatusMap = { [FileStatus.Success]: { - text: '发布成功', + text: t('发布成功'), theme: 'success', }, [FileStatus.Fail]: { - text: '发布失败', + text: t('发布失败'), theme: 'danger', }, [FileStatus.Edited]: { - text: '编辑待发布', + text: t('编辑待发布'), theme: 'warning', }, } diff --git a/web/src/polaris/configuration/fileGroup/detail/file/operation/Create.tsx b/web/src/polaris/configuration/fileGroup/detail/file/operation/Create.tsx index 721ba17a..793ba1ea 100644 --- a/web/src/polaris/configuration/fileGroup/detail/file/operation/Create.tsx +++ b/web/src/polaris/configuration/fileGroup/detail/file/operation/Create.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { DuckCmpProps, purify } from 'saga-duck' import Duck from './CreateDuck' @@ -21,7 +23,7 @@ export default function Create(props: DuckCmpProps) { store={store} dispatch={dispatch} size={'l'} - title={data.name ? '编辑配置文件' : '新建配置文件'} + title={data.name ? t('编辑配置文件') : t('新建配置文件')} > @@ -59,7 +61,7 @@ const CreateForm = purify(function CreateForm(props: DuckCmpProps) { return ( <> - + - + { if (val.lastIndexOf('.') === -1) { - format.setValue("text") + format.setValue('text') return } const suffix = val.substring(val.lastIndexOf('.') + 1) - if (suffix === "") { - format.setValue("text") + if (suffix === '') { + format.setValue('text') } else { format.setValue(suffix) } }} - placeholder={'允许数字、英文字母、.、-、_,限制128个字符'} + placeholder={t('允许数字、英文字母、.、-、_,限制128个字符')} size={'l'} /> {/* - - */} - - + + */} + + - + diff --git a/web/src/polaris/configuration/fileGroup/detail/file/operation/CreateDuck.ts b/web/src/polaris/configuration/fileGroup/detail/file/operation/CreateDuck.ts index fc30946f..dcd441c0 100644 --- a/web/src/polaris/configuration/fileGroup/detail/file/operation/CreateDuck.ts +++ b/web/src/polaris/configuration/fileGroup/detail/file/operation/CreateDuck.ts @@ -1,3 +1,4 @@ +import { t } from 'i18next' import { put, select } from 'redux-saga/effects' import { takeLatest } from 'redux-saga-catch' import { NamespaceItem } from '@src/polaris/namespace/PageDuck' @@ -72,10 +73,10 @@ export default class CreateDuck extends FormDialog { tags, }) if (configFile?.name) { - notification.success({ description: '编辑成功' }) + notification.success({ description: t('编辑成功') }) return true } else { - notification.error({ description: '编辑失败' }) + notification.error({ description: t('编辑失败') }) return false } } else { @@ -89,10 +90,10 @@ export default class CreateDuck extends FormDialog { content: '', }) if (configFile?.name) { - notification.success({ description: '创建成功' }) + notification.success({ description: t('创建成功') }) return true } else { - notification.error({ description: '创建失败' }) + notification.error({ description: t('创建失败') }) return false } } @@ -115,7 +116,7 @@ export default class CreateDuck extends FormDialog { selectors, } = this super.saga() - yield takeLatest(form.types.SET_VALUE, function* (action) { + yield takeLatest(form.types.SET_VALUE, function*(action) { if (!action.path || action.path?.indexOf('namespace') === -1) { return } @@ -127,18 +128,20 @@ export default class CreateDuck extends FormDialog { } = selector(yield select()) const { list } = yield getAllList(describeConfigFileGroups, {})({ namespace }) yield put({ - type: types.SET_OPTIONS, payload: { - ...options, configFileGroupList: list.map(item => { + type: types.SET_OPTIONS, + payload: { + ...options, + configFileGroupList: list.map(item => { const disabled = isReadOnlyConfigGroup(item) return { ...item, text: item.name, value: item.name, disabled, - tooltip: disabled && '该配置分组为只读配置分组', + tooltip: disabled && t('该配置分组为只读配置分组'), } - }) - } + }), + }, }) }) } @@ -170,7 +173,7 @@ export default class CreateDuck extends FormDialog { text: item.name, value: item.name, disabled, - tooltip: disabled && '该命名空间为只读命名空间', + tooltip: disabled && t('该命名空间为只读命名空间'), } }), configFileGroupList: configFileGroupList.map(item => { @@ -180,7 +183,7 @@ export default class CreateDuck extends FormDialog { text: item.name, value: item.name, disabled, - tooltip: disabled && '该配置分组为只读配置分组', + tooltip: disabled && t('该配置分组为只读配置分组'), } }), }, @@ -227,19 +230,19 @@ class CreateForm extends Form { } const validator = CreateForm.combineValidators({ name(v) { - if (!v) return '请填写文件名' + if (!v) return t('请填写文件名') if (v.split('/').filter(item => !item).length > 1) { - return '文件夹名字不可为空' + return t('文件夹名字不可为空') } }, namespace(v) { - if (!v) return '请选择命名空间' + if (!v) return t('请选择命名空间') }, group(v) { - if (!v) return '请选择分组' + if (!v) return t('请选择分组') }, format(v) { - if (!v) return '请选择格式' + if (!v) return t('请选择格式') }, }) diff --git a/web/src/polaris/configuration/fileGroup/detail/file/operation/GetFileTemplate.tsx b/web/src/polaris/configuration/fileGroup/detail/file/operation/GetFileTemplate.tsx index 6044bc10..1100d435 100644 --- a/web/src/polaris/configuration/fileGroup/detail/file/operation/GetFileTemplate.tsx +++ b/web/src/polaris/configuration/fileGroup/detail/file/operation/GetFileTemplate.tsx @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { Trans } from 'react-i18next' import React from 'react' import { DuckCmpProps, purify } from 'saga-duck' import Duck from './GetFileTemplateDuck' @@ -16,7 +18,14 @@ export default function GetFileTemplate(props: DuckCmpProps) { return