当前位置: 首页 > news >正文

浏览器默认语言与页面访问统计问题二三则

文章目录

  • 前言
  • 网站默认语言问题
  • 网站访问统计问题
    • Error: Empty components are self-closing
    • Error: A space is required before closing bracket
  • 总结

前言

看标题大概能猜到这是一篇杂合体的总结,是这两天处理网站遇到的小问题,怕过段时间再忘了所以总结到一起便于反过来查找问题解决方案,这个问题都是之前未曾接触过的,但遇到他们不用惧怕,只要假装自己能解决就行,这样稳扎稳打的找方案就能解决了。

网站默认语言问题

一个使用Nextjs框架编写的网站,支持中日英三种语言,如果访问主页面时未选择语言,则按照浏览器的语言来选择,这是合理的,一个人如果总用中文的浏览器,那么他在访问一个新网站时较大可能是想看中文的页面,所以我们优先选择当前浏览器的语言即可,默认跳转到指定语言的页面,选择语言的代码如下,是一个中间件 middleware.ts,问题在于默认语言为日文的浏览器,打开网页是英文的,这就得查查是因为什么了:

import { NextRequest, NextResponse } from 'next/server';
import acceptLanguage from 'accept-language';
import { fallbackLng, languages } from './app/i18n/settings';acceptLanguage.languages(languages);export const config = {// matcher: '/:lng*'matcher: ['/((?!api|_next/static|_next/image|images|svg|assets|favicon.ico|sw.js).*)']
};const cookieName = 'i18next';export function middleware(req: NextRequest) {let lng;// if (req.cookies.has(cookieName)) lng = acceptLanguage.get(req.cookies.get(cookieName)?.value);if (!lng) lng = acceptLanguage.get(req.headers.get('Accept-Language'));if (!lng) lng = fallbackLng;// Redirect if lng in path is not supportedif (!languages.some((loc) => req.nextUrl.pathname.startsWith(`/${loc}`))&& !req.nextUrl.pathname.startsWith('/_next')) {return NextResponse.redirect(new URL(`/${lng}${req.nextUrl.pathname}`, req.url));}if (req.headers.has('referer')) {const refererUrl = new URL(req.headers.get('referer') || 'zh');const lngInReferer = languages.find((l) => refererUrl.pathname.startsWith(`/${l}`));const response = NextResponse.next();if (lngInReferer) response.cookies.set(cookieName, lngInReferer);return response;}return NextResponse.next();
}

其中 matcher 是用来匹配路径的,这个配置表示,中间件会在请求的路径不包含特定字符串时触发。也就是说,路径不能包含指定的 api_next/static 等词缀。

网站语言看这一句 if (!lng) lng = acceptLanguage.get(req.headers.get('Accept-Language')); 就行了,它的含义是网站可以根据 Accept-Language 请求头来检测浏览器的首选语言,并返回相应语言的内容。

而我将浏览器默认语言设置为日语时,打开网站传递的 Accept-Language 内容为 ja,en;q=0.9,zh-CN;q=0.8,zh;q=0.7

根据你提供的 Accept-Language 内容 ja,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,以下是中间件的处理过程:

acceptLanguage.get(req.headers.get('Accept-Language')) 函数会根据 Accept-Language 头部的内容来选择最适合的语言。根据我浏览器传递的内容:

  • ja(日语)有最高的优先级。
  • en(英语)优先级为 0.9。
  • zh-CN(简体中文)优先级为 0.8。
  • zh(中文)优先级为 0.7。

由于 ja 的优先级是 1(默认)并且是最优的匹配,所以 acceptLanguage.get() 会选择 ja 作为首选语言。

但是可以还取决于 languages 的值,因为 acceptLanguage 是通过 languages 完成初始化的,而我查询了项目中它的值为 export const languages = ['jp', 'en', 'zh'];,发现问题了没有?日语浏览器将 ja 作为最优先展示语言,但是备选项里没有 ja,所以最终选出的结果是 en,这也就解释了为什么日语浏览器默认打开网页时显示英文页面的现象了。

日文的缩写通常是 “ja”,而不是 “jp”

  • “ja” 是 ISO 639-1 标准中日语的语言代码。
  • “jp” 通常用来表示 日本(Japan)的国家代码,在 ISO 3166-1 标准中使用。

因此,在国际化(i18n)和多语言网站的语言代码中,日文通常使用 “ja”

只要原因后就好修改了,改成ja也好,保持jp也罢,修正逻辑按照一致的顺序处理,问题也就能解决了。

网站访问统计问题

如果是一个网站开发者遇到这种问题,应该会有一个完整的解决方案,而我这种半吊子的网页开发人员,只想尽快的解决问题,所以我的搜索方向就是怎么尽快解决这个问题。起初搜到的方案是使用 Vercel Analytics 来查看,初始有个免费额度,超过25,000 events要进行收费,因为我的网站就部署在 Vercel 上,所以这种方案应该是最融洽的,查看每月的 events 使用量估算了费用,每月要 $100 以上,纠结中。

然后就搜到了 Google Analytics,介绍里说它完全免费,应用广泛,但是最近评价却不好,一方面是指责它收集隐私信息,另一方面是说它被很多浏览器插件屏蔽,导致无法准确统计,在抵制它的同时很多人都推荐使用了 Umami

Umami 是一个开源的简单、隐私友好的网站分析工具。它提供了类似于 Google Analytics 的功能,但更加专注于数据隐私,且无需依赖第三方 cookies。这使得 Umami 成为那些希望追踪用户活动但又需要遵守严格隐私法律(如 GDPR 或 CCPA)的个人和企业的理想选择。

Umami 是完全开源的(使用 MIT 许可证),代码可以在 GitHub 上找到并自行部署。客户端脚本文件仅约 2 KB,加载速度快,不会影响网页性能。时查看访问者活动,例如当前在线人数、浏览器、设备、地域等信息。

后端:Node.js 和 PostgreSQL。前端:基于 React 构建。部署:支持 Docker,配置简单。技术栈提起来挺简单,但是像我这么懒的人现在还不打算配置一遍,自己配置还要买服务器和数据库,因为我查到它有一个 Umami Cloud

Umami CloudUmami 的云托管服务,提供了一个简单、隐私友好的网站分析工具的在线版本。它允许用户通过 Umami 提供的 Web 界面,无需自行托管和管理服务器即可使用该分析工具。相比自己搭建 Umami,使用 Umami Cloud 可以节省大量的部署和维护成本,适合不想处理服务器配置的用户。

用户无需担心部署和维护服务器,Umami Cloud 提供了一个即开即用的服务,只需要注册并配置网站即可开始使用。与自托管的 Umami 一样,Umami Cloud 注重用户隐私,不收集个人可识别信息。它也不依赖 cookies 或第三方追踪,因此完全符合 GDPR 和其他隐私法规。

用户只需要将提供的 JavaScript 跟踪代码插入到网站页面,不需要任何后端代码,适合非技术用户。Umami Cloud 提供了不同的定价套餐,包括免费和付费版本。免费版本适合小型网站或个人使用,付费版本提供更多的功能和数据存储选项。

看起来数据大了还是得付钱,免费版本限制 100K events per month,Up to 3 websites,6 month data retention,对于我的网站来说还是不够用,但付费的价格相比Vercel算是降了不少,所以我把它的 跟踪代码 胡乱的集成到了我项目的 <head>...</head>中,进而引发了后面的问题

<script defer src="https://cloud.umami.is/script.js" data-website-id="YOUR_WEBSITE_ID"></script>

Error: Empty components are self-closing

这个错误的完整显示如下:

Failed to compile.
30:13  Error: Empty components are self-closing  react/self-closing-comp
info  - Need to disable some ESLint rules? Learn more here: https://nextjs.org/docs/basic-features/eslint#disabling-rulesELIFECYCLE  Command failed with exit code 1.
Error: Command "pnpm run build" exited with 1

我的代码开始写成了这样:

export default function RootLayout({children,params: { lng },
}: {children: React.ReactNode;params: { lng: LanguageType };
}) {return (<html lang={lng} className={myFont.variable}><head><script defer src="https://cloud.umami.is/script.js" data-website-id="YOUR_WEBSITE_ID"></script></head><body className="relative font-my">{children}</body></html>);
}

看着ChatGPT的解释我陷入了沉思,不过后来我明白了它的意思,这个错误是由于 ESLint 中的 react/self-closing-comp 规则引起的,该规则要求空的组件标签必须是自闭合的。

解决方法是检查报错所在的代码(通常是在第 30 行第 13 列),很可能是你有一个空的元素,例如:

<div></div>

它应该改成自闭合的写法:

<div />

所以我把代码改成了这样 <head><script defer src="https://cloud.umami.is/script.js" data-website-id="YOUR_WEBSITE_ID"/></head>,去掉了 </script> 然后就报了下面这个错。

Error: A space is required before closing bracket

完整错误如下:

Failed to compile.
30:120  Error: A space is required before closing bracket  react/jsx-tag-spacing
info  - Need to disable some ESLint rules? Learn more here: https://nextjs.org/docs/basic-features/eslint#disabling-rulesELIFECYCLE  Command failed with exit code 1.
Error: Command "pnpm run build" exited with 1

这次我还是没反应过来,经过ChatGPT解释发现,之前就已经给出准备的例子了,这个新的错误是由 ESLint 的 react/jsx-tag-spacing 规则引起的,它要求在自闭合标签的闭合括号前留一个空格。所以最终改成下面这样就没问题了

<head><script defer src="https://cloud.umami.is/script.js" data-website-id="YOUR_WEBSITE_ID" /></head>

真是一个空格也不能错啊~

总结

  • 网站的默认语言可以根据浏览器的设置语言来初始化,获取代码简化为 acceptLanguage.get(req.headers.get('Accept-Language'));
  • 网页统计可以使用 Vercel AnalyticsGoogle Analytics 或者 Umami
  • Vercel Analytics 与 Vercel 兼容性好,毕竟出自同一家班底,配合会比较顺畅,应该还会有自家产品的关联优化
  • Google Analytics 依赖 cookies,可能涉及隐私问题,数据存储在 Google 的服务器,由 Google 管理,功能全面,适合复杂需求
  • Umami 完全隐私友好,无 cookies,核心功能足够,但比 Google Analytics 少,可以用户自行托管,完全掌控

==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==

他日若是同淋雪,也算此生共白头。在两个人维系的关系中,一方的忍耐退让并不会让另一方生出善意,反而会导致对方以为之前的所有都是理所应当,进而变本加厉。总会有两个人不在一个频道上,你给她讲理,她跟你讲情,你跟她讲情,她跟你讲法,你跟她讲法,他跟你讲理,反正你永远对不了~

相关文章:

浏览器默认语言与页面访问统计问题二三则

文章目录 前言网站默认语言问题网站访问统计问题Error: Empty components are self-closingError: A space is required before closing bracket 总结 前言 看标题大概能猜到这是一篇杂合体的总结&#xff0c;是这两天处理网站遇到的小问题&#xff0c;怕过段时间再忘了所以总…...

用Python绘制一只懒羊羊

目录 一、准备工作 二、Turtle库简介 三、绘制懒羊羊的步骤 1. 导入Turtle库并设置画布 2. 绘制头部 3. 绘制眼睛 4. 绘制嘴巴 5. 绘制身体 6. 绘制四肢 7. 完成绘制 五、运行代码与结果展示 六、总结 在这个趣味盎然的技术实践中,我们将使用Python和Turtle图形…...

虹科分享 | 汽车NVH小课堂之听音辨故障

随着车主开始关注汽车抖动异响问题&#xff0c;如何根据故障现象快速诊断异响来源&#xff0c;成了汽修人的必修课。 一个比较常用的方法就是靠“听”——“听音辨故障”。那今天&#xff0c;虹科Pico也整理了几个不同类型的异响声音&#xff0c;一起来听听看你能答对几个吧 汽…...

论文速读|SigLIP:Sigmoid Loss for Language Image Pre-Training.ICCV23

论文地址&#xff1a;https://arxiv.org/abs/2303.15343v4 代码地址&#xff1a;https://github.com/google-research/big_vision bib引用&#xff1a; misc{zhai2023sigmoidlosslanguageimage,title{Sigmoid Loss for Language Image Pre-Training}, author{Xiaohua Zhai and…...

深度学习笔记——循环神经网络之LSTM

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍面试过程中可能遇到的循环神经网络LSTM知识点。 文章目录 文本特征提取的方法1. 基础方法1.1 词袋模型&#xff08;Bag of Words, BOW&#xff09;工作…...

算法整理:2-opt求解旅行商(Python代码)

文章目录 算法思想算法步骤代码1纯函数代码2纯函数数据可视化 算法思想 通过交换边进行寻优。 算法步骤 把初始解作为当前解 通过交换边生成新解 如果新解优于历史最优解&#xff0c;则更新当前解为新解 重复2&#xff0c;3&#xff0c;直到当前解交换了所有的边均不能改…...

状态模式

在软件开发过程中&#xff0c;我们经常会遇到这样的情况&#xff1a;一个对象的行为会随着其内部状态的改变而发生变化。例如&#xff0c;一个手机在不同状态下&#xff08;开机、关机、静音等&#xff09;对相同的操作&#xff08;如来电&#xff09;会有不同的反应。传统的解…...

RoHS 简介

RoHS&#xff08;Restriction of Hazardous Substances Directive&#xff0c;限制有害物质指令&#xff09;是欧盟制定的一项环保法规&#xff0c;旨在限制电气和电子设备中某些有害物质的使用&#xff0c;以减少这些产品对环境和人体健康的危害。 RoHS限制的有害物质及其限量…...

【Vim Masterclass 笔记26】S11L46:Vim 插件的安装、使用与日常管理

文章目录 Section 11&#xff1a;Vim PluginsS11L46 Managing Vim Plugins1 第三方插件管理工具2 安装插件使用的搜索引擎3 Vim 插件的安装方法4 存放 Vim 插件包的路径格式5 示例一&#xff1a;插件 NERDTree 的安装6 示例二&#xff1a;插件 ctrlp.vim 的安装7 示例三&#x…...

深度学习原理与Pytorch实战

深度学习原理与Pytorch实战 第2版 强化学习人工智能神经网络书籍 python动手学深度学习框架书 TransformerBERT图神经网络&#xff1a; 技术讲解 编辑推荐 1.基于PyTorch新版本&#xff0c;涵盖深度学习基础知识和前沿技术&#xff0c;由浅入深&#xff0c;通俗易懂&#xf…...

ELK环境搭建

文章目录 1.ElasticSearch安装1.安装的版本选择1.SpringBoot版本&#xff1a;2.4.2 找到依赖的spring-data-elasticsearch的版本2.spring-data-elasticsearch版本&#xff1a;4.1.3 找到依赖的elasticsearch版本3.elasticsearch版本&#xff1a;7.9.3 2.安装1.官方文档2.下载压…...

基于Springboot + vue实现的民俗网

“前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff1a;人工智能学习网站” &#x1f496;学习知识需费心&#xff0c; &#x1f4d5;整理归纳更费神。 &#x1f389;源码免费人人喜…...

第24篇 基于ARM A9处理器用汇编语言实现中断<六>

Q&#xff1a;怎样设计ARM处理器汇编语言程序使用定时器中断实现实时时钟&#xff1f; A&#xff1a;此前我们曾使用轮询定时器I/O的方式实现实时时钟&#xff0c;而在本实验中将采用定时器中断的方式。新增第三个中断源A9 Private Timer&#xff0c;对该定时器进行配置&#…...

【数据结构】_不带头非循环单向链表

目录 1. 链表的概念及结构 2. 链表的分类 3. 单链表的实现 3.1 SList.h头文件 3.2 SList.c源文件 3.3 Test_SList.c测试文件 关于线性表&#xff0c;已介绍顺序表&#xff0c;详见下文&#xff1a; 【数据结构】_顺序表-CSDN博客 本文介绍链表&#xff1b; 基于顺序表…...

golang 使用双向链表作为container/heap的载体

MyHeap&#xff1a;container/heap的数据载体&#xff0c;需要实现以下方法&#xff1a; Len&#xff1a;堆中数据个数 Less&#xff1a;第i个元素 是否必 第j个元素 值小 Swap&#xff1a;交换第i个元素和 第j个元素 Push&#xff1a;向堆中追加元素 Pop&#xff1a;从堆…...

C#集合操作优化:高效实现批量添加与删除

在C#中&#xff0c;对集合进行批量操作&#xff08;如批量添加或删除元素&#xff09;通常涉及使用集合类型提供的方法和特性&#xff0c;以及可能的循环或LINQ查询来高效地处理大量数据。以下是一些常见的方法和技巧&#xff1a; 批量添加元素 使用集合的AddRange方法&#x…...

142.WEB渗透测试-信息收集-小程序、app(13)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;141.WEB渗透测试-信息收集-小程序、app&#xff08;12&#xff09; 软件用法&#xff0c…...

24.日常算法

1. 数组中两元素的最大乘积 题目来源 给你一个整数数组 nums&#xff0c;请你选择数组的两个不同下标 i 和 j&#xff0c;使 (nums[i]-1)*(nums[j]-1) 取得最大值。请你计算并返回该式的最大值。 示例 1&#xff1a; 输入&#xff1a;nums [3,4,5,2] 输出&#xff1a;12 解释…...

分布式理解

分布式 如何理解分布式 狭义的分布是指&#xff0c;指多台PC在地理位置上分布在不同的地方。 分布式系统 分布式系**统&#xff1a;**多个能独立运行的计算机&#xff08;称为结点&#xff09;组成。各个结点利用计算机网络进行信息传递&#xff0c;从而实现共同的“目标或者任…...

wordpress调用指定ID页面的链接

在WordPress中&#xff0c;如果你想调用一个指定ID的页面链接&#xff0c;可以使用以下几种方法&#xff1a; 方法一&#xff1a;使用页面ID 你可以直接使用页面的ID来生成链接。例如&#xff0c;如果你想链接到ID为123的页面&#xff0c;可以使用以下代码&#xff1a; <…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving

地址&#xff1a;LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂&#xff0c;正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...

【深度学习新浪潮】什么是credit assignment problem?

Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...

sshd代码修改banner

sshd服务连接之后会收到字符串&#xff1a; SSH-2.0-OpenSSH_9.5 容易被hacker识别此服务为sshd服务。 是否可以通过修改此banner达到让人无法识别此服务的目的呢&#xff1f; 不能。因为这是写的SSH的协议中的。 也就是协议规定了banner必须这么写。 SSH- 开头&#xff0c…...

EasyRTC音视频实时通话功能在WebRTC与智能硬件整合中的应用与优势

一、WebRTC与智能硬件整合趋势​ 随着物联网和实时通信需求的爆发式增长&#xff0c;WebRTC作为开源实时通信技术&#xff0c;为浏览器与移动应用提供免插件的音视频通信能力&#xff0c;在智能硬件领域的融合应用已成必然趋势。智能硬件不再局限于单一功能&#xff0c;对实时…...