Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
使用 i 翻译你的 React 项目从未如此简单_创想鸟

使用 i 翻译你的 React 项目从未如此简单

使用 i 翻译你的 react 项目从未如此简单

说疯狂的开发者!

今天我将向您展示,将整个项目翻译成 react 从未像现在这样容易。但首先您需要知道为什么这很重要。

当人们开始编程时,代码文本和消息通常使用葡萄牙语(pt-br)。将项目翻译成其他语言从来都不是优先事项,并且被认为是复杂或不必要的。

那么为什么它会相关呢?

这取决于你的实际情况。以下是您应该考虑此过程的一些原因:

公司需要
可能是您工作的公司或您拥有的某些 saas 开始在另一个国家/地区运营并且有此需求。具有此功能的产品有巨大的差异。

申请国​​际职位空缺
如果您正在申请国际职位空缺,拥有包含国际化项目的作品集可以给您带来引人注目的亮点。这表明您已准备好从事全球项目,并且不像大多数人一样懒惰。

你永远不会学太多
国际化不仅是一种特征,也是一种重要的学习经历。这是您的技能和工具库中的另一种武器。

过去是如何做到的?

项目翻译已经是个老问题了。人们在 html 中选择了该国家的国旗,供人们选择,并在代码中用 if 填充以了解将显示哪些文本。
这是非常被忽视的。网站是用单一语言制作的,翻译是随意添加的。如果是在后端,交易会更糟糕。

随着互联网的全球化,对多语言软件的需求不断增长,带来了针对国际化的特定工具。像 gnu gettext 这样的解决方案出现在后端,随后出现了像 i18next 和 react-intl 这样的前端库。然后疑问就来了…

i18next 对比react-intl:选择哪一个?

i18next:这个出现于 2011 年,它是一个 npm 包,适用于客户端的 node.js 和 spa。社区采纳了它,并最终于2015年在react-i18next lib中制作了react版本。因此,作为积极和消极的点,我们有:

优点:灵活性、路上时间(自 2011 年起)、庞大的生态系统(一次学习,随处翻译)和自动回退。缺点:学习曲线。有很多文档需要阅读,但并不是您需要的所有内容都在那里。

react-intl:formatjs 项目的一部分,遵循国际 javascript api 标准,确保与现代浏览器的兼容性。

优点:与 ecmascript 标准保持一致,集成简单。缺点:灵活性较差,插件支持较少。

我们将使用哪一个?

i18下一个我的朋友们!我总是建议阅读文档来开始,但让我们看看 doido 的指南!

使用 i18next 国际化 react 应用程序

安装:

   npm install i18next i18next-chained-backend i18next-http-backend i18next-resources-to-backend react-i18next next-i18next 

配置:创建一个i18n.js来配置i18next。

   import i18n from 'i18next';   import { initreacti18next } from 'react-i18next';   import backend from 'i18next-http-backend';   import languagedetector from 'i18next-browser-languagedetector';   i18n     .use(backend)     .use(languagedetector)     .use(initreacti18next)     .init({ fallbacklng: 'en', interpolation: { escapevalue: false } });   export default i18n;

translations:在 locales/en/translation.json 和 locales/pt/translation.json 中创建翻译文件。

   {     "welcome": "welcome to our application!",     "login": "login"   }

翻译的使用:在 react 中使用 usetranslation 钩子。

   import react from 'react';   import { usetranslation } from 'react-i18next';   function app() {     const { t } = usetranslation();     return (       

{t('welcome')}

); } export default app;

语言更改:允许用户更改语言。

   import react from 'react';   import { usetranslation } from 'react-i18next';   function languageswitcher() {     const { i18n } = usetranslation();     const changelanguage = (lng) => i18n.changelanguage(lng);     return (       
); } export default languageswitcher;

这就是全部吗?

当然不是,我现在向您展示我在 crazystack 项目中做了什么。首先,我在 nextjs 中做了一个不同的配置,采用了我在项目本身的公共文件夹中定义的静态 json!看看:

import i18next from "i18next";import chainedbackend from "i18next-chained-backend";import httpbackend from "i18next-http-backend";import resourcestobackend from "i18next-resources-to-backend";import { initreacti18next } from "react-i18next";import { defaulttexts } from "./defaulttexts";i18next  .use(chainedbackend)  .use(initreacti18next)  .init({    lng: "pt-br",    fallbacklng: "pt-br",    interpolation: {      escapevalue: false,    },    compatibilityjson: "v3",    react: {      //wait: true,//usar no react native      usesuspense: false,    },    backend: {      backends: [httpbackend, resourcestobackend(defaulttexts)],      backendoptions: [        {          loadpath: `${process.env.next_public_url}/{{lng}}/{{ns}}.json`,        },      ],    },  });

然后我创建了一个上下文 api 来保存语言并在整个项目中访问它。从进口开始

2. 进口

import { usetranslation } from "react-i18next";import { createcontext, usestate, usecontext } from "react";

usetranslation:react-i18next 挂钩来访问翻译功能。在这里,您将在项目中几乎每个 jsx 组件中使用它。createcontext、usestate、usecontext:用于创建和使用上下文以及管理状态的 react 函数。

3. 上下文创建

const i18ncontext = createcontext({} as any);

创建上下文来通过 dom 存储和提供数据(例如当前语言)。

4. 环境检查

export const isbrowser = typeof window !== "undefined";

此行检查代码是否在浏览器中运行(而不是在服务器上),这对于处理 localstorage 等特定于客户端的功能至关重要。

5.i18nprovider组件

export const i18nprovider = ({ children }: any) => {  const { i18n } = usetranslation() || {};  const [currentlanguage, setcurrentlanguage] = usestate(    formatlanguagefromi18n(i18n?.language)  );  const changelanguage = (language) => {    setcurrentlanguage(language);    i18n?.changelanguage?.(formatlanguagefromselect(language));    localstorage.setitem("language", formatlanguagefromselect(language));  };  return (          {children}      );};

这个组件是一个provider,它包装了react组件树并提供了语言的当前状态以及更改它的函数。

usetranslation:从react-i18next库中检索i18n对象,其中包含有关当前语言的信息。currentlanguage:存储当前语言的state,根据i18n检测到的语言进行初始化。changelanguage:更改语言的函数,这也会将选择保存在 localstorage 中,以便在页面重新加载之间保持持久性。

6. 挂钩使用i18n

export const usei18n = () => {  if (!isbrowser) {    return {      currentlanguage: "pt-br",      setcurrentlanguage: () => {},      changelanguage: () => {},    };  }  return usecontext(i18ncontext);};

这个钩子可以轻松访问任何组件中的国际化上下文。

检查您是否在浏览器中(isbrowser)。如果没有,则返回默认值,以避免服务器端出错。如果在浏览器中,则消耗并返回 i18ncontext 上下文。

7. 转换图

const countrytolanguage = {  br: "pt-br",  us: "en",};const languagetocountry = {  "pt-br": "br",  en: "us",};

这些对象将国家/地区代码映射到语言代码,反之亦然,从而可以轻松地在不同约定之间格式化语言代码。

8. 格式化函数

export const formatlanguagefromi18n = (language) => languagetocountry[language];export const formatlanguagefromselect = (language) => countrytolanguage[language];

这些函数根据需要格式化语言环境。 formatlanguagefromi18n 将语言代码转换为国家/地区代码,而 formatlanguagefromselect 则进行反向转换。

完整代码

"use client";import { usetranslation } from "react-i18next";import { createcontext, usestate, usecontext } from "react";const i18ncontext = createcontext({} as any);export const isbrowser = typeof window !== "undefined";export const i18nprovider = ({ children }: any) => {  const { i18n } = usetranslation() || {};  const [currentlanguage, setcurrentlanguage] = usestate(    formatlanguagefromi18n(i18n?.language)  );  const changelanguage = (language) => {    setcurrentlanguage(language);    i18n?.changelanguage?.(formatlanguagefromselect(language));    localstorage.setitem("language", formatlanguagefromselect(language));  };  return (          {children}      );};export const usei18n = () => {  if (!isbrowser) {    return {      currentlanguage: "pt-br",      setcurrentlanguage: () => {},      changelanguage: () => {},    };  }  return usecontext(i18ncontext);};const countrytolanguage = {  br: "pt-br",  us: "en",};const languagetocountry = {  "pt-br": "br",  en: "us",};export const formatlanguagefromi18n = (language) => languagetocountry[language];export const formatlanguagefromselect = (language) => countrytolanguage[language];

然后我改变了导航栏

在代码中,我使用国家/地区下拉菜单选择语言。看看:

"use client";//@ts-nocheckimport { header, flex, logo, profile, notificationsnav, searchbar } from "@/shared/ui";import { usebreakpointvalue, icon, iconbutton, usemediaquery } from "@chakra-ui/react";import { rimenuline } from "react-icons/ri";import { useauth, usesidebardrawer } from "@/shared/libs";import { useeffect, usestate } from "react";import { countrydropdown } from "react-country-region-selector";import { theme } from "@/application/theme";import { formatlanguagefromi18n, usei18n } from "@/application/providers/i18nprovider";import { usetranslation } from "react-i18next";export const navbar = ({ showlogo = true }) => {  const { isauthenticated } = useauth() || {};  const { i18n } = usetranslation();  const { changelanguage, setcurrentlanguage } = usei18n() || {};  const { onopen = () => {}, onclose } = usesidebardrawer() || {};  const isdesktopversion = usebreakpointvalue({ base: false, lg: true });  const [country, setcountry] = usestate(formatlanguagefromi18n(i18n?.language));  useeffect(() => {    return () => {      onclose?.();    };  }, []);  const dropdown = countrydropdown as any;  useeffect(() => {    const language = localstorage.getitem("language");    if (language) {      setcountry(formatlanguagefromi18n(language));      setcurrentlanguage(language);      i18n?.changelanguage?.(language);    }  }, []);  return (    
{isauthenticated && !isdesktopversion && ( <iconbutton aria-label="open sidebar" fontsize="24" icon={} variant="unstyled" onclick={onopen} mr="1" mt={2} /> )} {/* {islargerthan560 && ( )} */} {isauthenticated && ( {/* */} { setcountry(val); changelanguage(val); }} labeltype="short" valuetype="short" showdefaultoption defaultoptionlabel="selecione o idioma" whitelist={["us", "br"]} style={{ backgroundcolor: theme.colors.secondary[400], padding: 10, width: 60, marginright: 15, borderradius: 8, }} /> )}
);};

导入和初始设置:

useauth:检查用户是否经过身份验证。usebreakpointvalue:根据屏幕大小决定是否显示桌面版本。usestate:设置国家/语言(国家)的初始状态,使用formatlanguagefromi18n函数格式化i18n的当前语言useeffect:第一个效果是在卸载组件时清除侧边栏(onclose)。第二个效果检查语言是否保存在 localstorage 中,如果是,则更新国家/地区状态并更改应用程序中的语言。

语言下拉菜单:

下拉列表是使用react-country-region-selector库的countrydropdown组件实现的,该组件被定制为用作语言选择器。value={country}:下拉列表中选择的值由国家/地区控制。onchange={(val) => { … }}:当下拉值改变时,更新国家状态,并调用changelanguage函数更改应用程序语言。whitelist={[“us”, “br”]}:将下拉选项限制为“us”(英语)和“br”(葡萄牙语)。style={…}:下拉菜单的自定义内联样式,使用主题的颜色和间距。语言选择器行为:下拉列表允许用户选择首选语言,并且此选择会保留在 localstorage 中。更改语言时,下拉列表会反映此更改,并且应用程序会更新为使用新选择的语言。要在文章中包含您在图像中提供的代码片段,您可以遵循以下格式:

以及如何更改文本?

从一个组件到另一个组件,我都遵循相同的过程。下面的代码展示了如何根据本地化密钥用动态翻译替换静态文本:

import { Divider } from "@chakra-ui/react";import { IoExitOutline } from "react-icons/io5";import { useRouter } from "next/navigation";import { useTranslation } from "react-i18next";  // Importando o hook useTranslationtype ProfileProps = {  showProfileData?: boolean;};export const Profile = ({ showProfileData }: ProfileProps) => {  const { t } = useTranslation(["PAGES"]);  // Obtendo a função t para tradução  const { user, logout } = useAuth() || {};  const router = useRouter();  const { showUserMenu, setShowUserMenu } = useProfile();  return (          {/* Outras partes do componente */}                                {t("PAGES:HOME_PAGE.logout", { defaultValue: "Sair" })}  // Chave de tradução com valor padrão                    );};

在此示例中,usetranslation 挂钩用于加载 pages:home_page.logout 翻译键。如果未找到该密钥,将显示默认文本“退出”。

结论

这个想法可以应用于任何静态文本组件。只需使用 usetranslation 钩子即可。
国际化您的应用程序可以打开全球市场的大门,突出您的投资组合并提高您的技能。在 i18next 和 react-intl 之间进行选择取决于您项目的具体需求,但对于那些想要入门的人来说,两者都是很好的选择。

课程建议

2022 年,我创建了crazystack 训练营。在其中,我展示了在线服务调度系统的 2 个完整应用程序,应用了设计模式、简洁架构、功能切片设计、solid、ddd 以及单元、集成和 e2e 测试等先进概念。

在第一个应用程序中,您将学习如何在 node.js 生态系统中构建 rest api。将创建涉及复杂业务规则的用例,例如列出可用时间、根据预订生成订单、忠诚度系统、佣金、付款、客户评论等等。一切都在 typescript 中完成并使用非关系数据库 mongodb。

在第二个应用程序中,您将学习如何在 react.js 生态系统中构建管理面板来查看图表和操作记录。一切都是通过 typescript 和 next.js 框架完成的。此外,还将使用chakra ui可视化组件库,将原子设计概念应用于创建的组件。要了解更多信息,请访问crazystack.com.br。

以上就是使用 i 翻译你的 React 项目从未如此简单的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1490791.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
使用人工智能检测过时的描述
上一篇 2025年12月19日 13:27:01
初学者 JavaScript
下一篇 2025年12月19日 13:27:13

相关推荐

  • 如何在微服务之间共享静态数据

    如何在微服务之间共享静态数据如何在微服务之间共享静态数据如何在微服务之间共享静态数据如何在微服务之间共享静态数据

    微服务架构的本质决定了微服务之间无法直接共享静态变量。正如上面摘要所说,每个微服务都是一个独立的进程,拥有自己的内存空间,静态变量只在其所属的进程内有效。试图在一个微服务中访问另一个微服务的静态变量,就像试图在一个独立的Java程序中访问另一个程序的变量一样,是不可能的。 微服务架构的独立性 微服务…

    2026年9月25日 • 用户投稿
    100
  • VSCode怎样用调试启动参数自定义运行时环境变量 VSCode启动参数自定义环境变量的创新用法​

    vscode允许通过launch.json中的”env”属性直接设置环境变量,或使用”envfile”指定.env文件来加载变量。1. 直接在launch.json中定义”env”属性可为调试会话注入键值对形式的环境变量,适用于…

    2026年9月25日
    300
  • Debian环境下MongoDB如何进行性能调优

    在debian环境下进行mongodb性能调优,可以参考以下步骤和建议: 硬件和配置优化 选择合适的硬件:根据应用需求选择合适的CPU、内存和存储设备。配置内存:确保MongoDB有足够的内存来缓存数据和索引,减少磁盘I/O。使用SSD:SSD硬盘比传统硬盘提供更快的读写速度,显著提升数据库性能。 …

    2026年9月24日
    100
  • MongoDB在Debian上如何进行集群搭建

    在debian上搭建mongodb集群涉及多个步骤,包括安装、配置、启动各个组件以及设置副本集和分片。以下是一个基本的指南: 1. 安装MongoDB 首先,确保你的Debian系统是最新的,然后安装MongoDB。 sudo apt updatesudo apt upgradesudo apt i…

    2026年9月24日
    300
  • 如何在Debian上配置MongoDB审计日志

    在debian上配置mongodb审计日志可以帮助你监控和记录数据库的活动,从而提高安全性。以下是详细的步骤来配置mongodb审计日志: 1. 安装MongoDB 首先,确保你已经在Debian上安装了MongoDB。如果没有安装,可以使用以下命令进行安装: sudo apt updatesudo…

    2026年9月24日
    100
  • 袋鼠数据库工具 8.90.1 版已上线

    袋鼠数据库工具 8.90.1 版已上线袋鼠数据库工具 8.90.1 版已上线袋鼠数据库工具 8.90.1 版已上线袋鼠数据库工具 8.90.1 版已上线

    袋鼠数据库工具 是一款由 ai 驱动的主流数据库系统客户端,支持多种数据库类型,包括 mariadb、mongodb、mysql、oracle、postgresql、redis、sqlite、sqlserver 等,具备建表、数据查询、模型设计、结构同步、数据导入导出等丰富功能。兼容 windows…

    2026年9月24日 • 用户投稿
    100
  • TradingAgents-CN— 中文多智能体金融交易决策框架

    TradingAgents-CN— 中文多智能体金融交易决策框架TradingAgents-CN— 中文多智能体金融交易决策框架TradingAgents-CN— 中文多智能体金融交易决策框架TradingAgents-CN— 中文多智能体金融交易决策框架

    TradingAgents-CN是什么 tradingagents-cn是基于多智能体大模型的中文金融交易决策框架,在tauricresearch/tradingagents的基础上进行了开发,为中文用户提供了完整的文档体系和本地化支持。框架模拟真实交易公司的专业分工和协作决策流程,通过多个专业化a…

    2026年9月24日 • 用户投稿
    900
  • 如何在ThinkPHP6中使用MongoDB进行数据存储

    随着互联网的不断发展,数据的存储和处理越来越成为一个重要的方向。而mongodb则是一种适用于大规模数据和高性能应用场景的nosql数据库,它的高性能和可扩展性得到了众多开发者的拥护。在这篇文章中,我们将介绍如何在thinkphp6中使用mongodb进行数据存储。 一、安装MongoDB拓展 首先…

    用户投稿 2026年9月24日
    100
  • Spring Boot集成MongoDB Atlas:正确配置与故障排除

    本教程详细指导如何在Spring Boot应用中正确配置与连接MongoDB Atlas集群。我们将重点讲解如何获取并使用正确的Atlas连接URI,安全地处理用户认证信息,以及准确指定目标数据库。通过实例代码和常见错误排查,帮助开发者避免连接失败,确保应用与MongoDB Atlas的顺畅集成。 …

    2026年9月22日
    600
  • Laravel自定义用户提供者?用户提供者怎样实现?

    自定义用户提供者可集成非Eloquent模型与多种数据源,如NoSQL、API、LDAP或文件,通过实现UserProvider和Authenticatable接口,灵活处理用户检索与密码验证,解决认证问题需确保接口方法正确实现并合理配置。 自定义 Laravel 用户提供者允许你使用非 Eloqu…

    2026年9月11日
    100
  • 数据量大的App制作,数据库如何选型?

    在开发处理大量数据的应用程序时,数据库的选择至关重要。选择一个合适的数据库不仅能确保数据的存储效率和安全性,还能提升应用程序的整体性能和用户体验。以下将从几个关键方面探讨如何为数据量大的app选择合适的数据库。 首先,考虑数据量的大小。 对于数据量庞大的应用程序,首要考虑的是数据库的存储能力和扩展性…

    2026年9月7日
    000
  • 在 Spring Boot Web 应用程序中序列化枚举

    枚举类型在定义应用程序域内有限且明确的值集方面非常有效,有助于避免代码中出现无效状态。 应用场景 以下以一个Spring Boot 3.3.x 和 MongoDB 实现的笔记Web应用为例,演示枚举值的序列化和反序列化方法。 我们将定义一个Type枚举,表示待办事项的类型:事件和活动。 public…

    2026年9月7日
    000
  • 玩转mongoDB(五):mongoDB 3.0+ 查询性能分析

    为了展示mongodb的性能分析方法,我们首先创建一个包含200万个文档的集合。(在我的电脑上,插入过程大约耗时15分钟。如果您想插入更多文档,只要有耐心等待即可。) 为了演示的效果,我们先来创建一个有200万个文档的记录。(我自己的电脑耗了15分钟左右插入完成。如果你想插更多的文档也没问题,只要有…

    2026年9月7日
    200
  • MySQL如何监控数据库性能_有哪些常用监控工具?

    MySQL如何监控数据库性能_有哪些常用监控工具?MySQL如何监控数据库性能_有哪些常用监控工具?MySQL如何监控数据库性能_有哪些常用监控工具?MySQL如何监控数据库性能_有哪些常用监控工具?

    mysql性能监控需关注关键指标、使用合适工具、设置告警并注意易忽略细节。一、最关键监控指标包括连接数、qps/tps、慢查询数量、innodb读写情况、锁等待与死锁;二、常用工具包括show processlist、pmm、zabbix、prometheus+grafana、pt-query-di…

    2026年9月5日 • 用户投稿
    100
  • 高效单元测试:使用Helmich/Mongomock模拟MongoDB

    我最近参与开发一个基于mongodb的项目,其中涉及大量的数据库操作。为了保证代码质量,我们需要编写全面的单元测试。然而,直接使用真实的mongodb进行单元测试带来了诸多不便:测试速度慢,需要搭建和维护测试数据库,以及测试环境的依赖性等问题。这些问题严重影响了开发效率和测试的稳定性。 为了解决这个…

    用户投稿 2026年9月4日
    200
  • 这次简单多了,最新版 MongoDB 安装

    这次简单多了,最新版 MongoDB 安装这次简单多了,最新版 MongoDB 安装这次简单多了,最新版 MongoDB 安装这次简单多了,最新版 MongoDB 安装

    在 windows 10 系统上安装 mongodb 4.0.1 版本变得更为简便,基本上一路点击“下一步”就能完成安装,不再需要繁琐的配置。 首先,访问 MongoDB 官方网站,下载 MongoDB 4.0.1 版本,网址如下: https://www.php.cn/link/9cba84644…

    2026年9月4日 • 用户投稿
    300
  • Web全栈开发者如何提升技能,获得更好的就业机会?

    Web全栈开发:提升技能,拓展职业发展 如何提升Web全栈开发技能,从而获得更理想的就业机会,是许多开发者共同关注的问题。本文将探讨有效提升全栈开发能力的途径,帮助您在竞争激烈的就业市场中脱颖而出。 虽然无法提供具体的全栈学习路线图,但我们可以从编程大师的经验中汲取灵感。 (此处省略图片,但其核心思…

    2026年9月2日
    200
  • MongoDB ObjectId类型转换报错:如何正确处理String到ObjectId的转换?

    MongoDB ObjectId类型转换错误排查与解决 在MongoDB数据库操作中,ObjectId类型常常引发转换错误。ObjectId是MongoDB文档的唯一标识符,与普通字符串不同,直接转换可能导致异常。本文针对“将字符串转换为ObjectId时报错”的问题提供解决方案。 用户反馈的错误信…

    2026年9月1日
    000
  • MongoDB ObjectId类型转换错误:字符串转ObjectId失败如何排查?

    MongoDB ObjectId转换错误排查指南 在使用MongoDB时,经常需要将字符串类型的ID转换为ObjectId类型。如果转换失败,将会影响数据库操作。本文针对字符串转ObjectId报错问题提供排查方法。 问题:将字符串转换为ObjectId时报错,错误信息未提供,但可能原因与字符串ID…

    2026年9月1日
    100
  • 如何在CentOS和Fedora上将Node.js程序与MongoDB连接

    本篇文章将介绍关于将node.js应用程序与mongodb连接的方法。另外,在centos和redhat系统上使用mongoose节点应用程序为nodejs配置mongodb驱动器。 步骤1:首要条件 我们假设系统上已经安装了node.js和mongodb。如果没有安装,可以参考下面的文章完成所需的…

    2026年8月30日
    000

发表回复

登录后才能评论
关注微信