Civitai汉化v2

汉化Civitai

// ==UserScript==
// @name        Civitai汉化v2
// @description  汉化Civitai
// @namespace   Violentmonkey Scripts
// @match       https://civitai.com/
// @match       https://civitai.com/*
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @author      Ella Maietta & ii3600
// @version     2.1.1
// @license     All Rights Reserved

// ==/UserScript==
(function() {
  'use strict';

  if (!GM_getValue("userConfirmed")) {
    fetchContent("https://raw.githubusercontent.com/Guyungy/AIGC-knowbase/main/civitai.md", function(htmlContent) {
      let overlay = document.createElement("div");
      let contentContainer = document.createElement("div"); 

      overlay.style.position = "fixed";
      overlay.style.top = "0";
      overlay.style.left = "0";
      overlay.style.width = "100%";
      overlay.style.height = "100%";
      overlay.style.backgroundColor = "rgba(0,0,0,0.5)";
      overlay.style.zIndex = "9999";
      overlay.style.textAlign = "center";
      overlay.style.paddingTop = "20%";

      contentContainer.style.display = "inline-block";
      contentContainer.style.backgroundColor = "white";
      contentContainer.style.borderRadius = "10px";
      contentContainer.style.border = "2px solid black";
      contentContainer.style.padding = "20px";
      overlay.appendChild(contentContainer); 

      let contentBox = document.createElement("div");
      contentBox.innerHTML = htmlContent;
      contentContainer.appendChild(contentBox); 

      let confirmBtn = document.createElement("button");
      confirmBtn.innerText = "开始使用";
      confirmBtn.style.marginTop = "50px";
      confirmBtn.style.fontSize = "20px";
      confirmBtn.style.padding = "15px 30px";
      confirmBtn.style.borderRadius = "10px";
      confirmBtn.style.backgroundColor = "#2196F3";
      confirmBtn.style.color = "white";
      confirmBtn.style.cursor = "pointer";
      confirmBtn.style.transition = "transform 0.2s";
      confirmBtn.onmouseover = function() {
        this.style.transform = "scale(1.05)";
      }
      confirmBtn.onmouseout = function() {
        this.style.transform = "scale(1)";
      }
      contentContainer.appendChild(confirmBtn); 

      document.body.appendChild(overlay);

      confirmBtn.onclick = function() {
        GM_setValue("userConfirmed", true);
        overlay.remove();
      };
    });
  }


  const i18n = new Map([
    ['status', '状态'],
    ['Get', '获取'],
    ['Quick Search', '快速搜索'],
    ['Models', '模型'],
    ['Images', '图片'],
    ['Posts', '帖子'],
    ['Articles', '文章'],
    ['Users', '用户'],
        // 浏览方式

    ['models','模型'],
    ['images','图像'],
    ['videos','视频'],
    ['home','主页'],
    ['posts','张贴板'],
    ['articles','文章'],
    ['bounties','悬赏'],
    ['challenges','挑战赛'],
    ['events','平台事件'],
    ['shop','商店'],
    ['Create','开始创作'],
    ['Followed','仅查看已关注的人'],
    ['Everyone','查看所有人'],
    ['Filters','筛选'],
    ['Time period','时间范围'],
    ['Clear all filters','重置筛选'],
    ['Post','发布'],
    ['Videos','视频'],
    ['lmages','图片'],
    ['Generate','在线创作'],
    ['generate','在线创作'],
    ['Upload a Model','上传模型'],
    ['Browsing Level','可见内容等级'],
    ['Select the levels of content you want to see','选择要查看的内容级别'],
    ['Blur mature content','模糊成人内容'],
    ['Rating Game','评级测试小游戏'],
    ['Collections','收藏'],
    ['File format','文件格式'],
    ['Modifiers','修饰词'],
    ['Most Collected','收藏次数最多'],
    ['Most Liked','点赞最多'],
    ['Most Downloaded','下载最多'],
    ['Highest Rated','评分最高'],
    ['Write an Article','写一篇文章'],
    ['',''],
    ['',''],

        // 消息
    ['Notifications','通知列表'],
    ['Hide Read','隐藏已读'],
    ['Mark all as read','全部标记为已读'],
    ['Notification settings','通知设置'],

    ['announcements','公告'],
    ['Comments','评论'],
    ['Updates','更新'],
    ['Bounties','悬赏'],
    ['Buzz','打赏'],
    ['System','系统信息'],
    ['All caught up! Nothing to see here','没有可看的了~'],
    ['model has a new version','发布了新的版本'],
    ['released a new LoRA','发布了新的lora'],


    ['Base Model','基本模型'],
    ['Training','训练参数'],
    ['Usage Tips','使用参考'],
    ['Commission','委托'],
    ['Trigger Words','触发词'],

    ['Train a ','训练'],
    ['',''],
    ['',''],
    ['',''],

    ['Highest Rated','最高评分'],
    ['Most Downloaded','最多下载'],
    ['Most Liked','最多点赞'],
    ['Most Discussed','最多讨论'],
    ['Most Bookmarks','最多收藏'],
    ['Newest','最新的'],
    //时间筛选
    ['Day', '日'],
    ['Week', '周'],
    ['Month', '月'],
    ['Year', '年'],
    ['All  Time', '全部时间'],
    //筛选菜单

    ['Early Access', '早期访问'],
    ['Model types', '模型类型'],
    ['Checkpoint ', '大模型'],
    ['Model status', '模型类型'],
    ['Base model', '底模版本'],
    ['Clear Filters', '取消筛选'],

    //菜单
    ['guide','指南'],
    ['View more','查看更多'],
    ['Upload a model','上传模型'],


    //登录相关
    ['Your profile','您的个人资料'],
    ['My collections','我的收藏'],
    ['Liked models','喜欢的模型'],
    ['Bookmarked articles','收藏的文章'],
    ['Leaderboard','排行榜'],
    ['Hidden models','隐藏的模型'],
    ['Creators you follow','您关注的创作者'],
    ['Download history','下载历史'],
    ['Questions','问题'],
    ['Beta','测试版'],
    ['Dark mode','深色模式'],
    ['Account settings','账户设置'],
    ['Logout','登出'],

    //个人资料
    ['My 图片','我的图片'],
    ['My Reactions','我的反应'],
    ['Most Reactions','最多反应'],
    ['Most Comments','最多评论'],
    ['No results found','没有找到结果'],
    ['Stats','统计'],
    ['Published','已发布'],

    // 设置
    ['Creator Profile','创作者档案'],
    ['Add Link','添加链接'],
    ['Social','社交'],
    ['Links','链接'],
    ['You have not added any social links','您还没有添加任何社交链接'],
    ['Sponsorship','赞助'],
    ['You have not added any sponsorship links','您还没有添加任何赞助链接'],
    ['Browsing Settings','浏览设置'],
    ['Image Preferences','图片偏好设置'],
    ['Autoplay GIFs','自动播放GIFs'],
    ['Preferred Format','偏好格式'],
    ['Unoptimized (jpeg, png)','未优化 (jpeg, png)'],
    ['模式l 文件 Preferences','模型文件偏好设置'],
    ['Preferred Format','偏好格式'],
    ['Preferred Size','偏好大小'],
    ['Preferred FP','偏好FP'],
    ['Early Access Features','早期访问功能'],
    ['Quick Search (Beta)','快速搜索 (测试版)'],
    ['AI Resource Identifier','AI资源标识符'],
    ['Show the Civitai AIR on resources to make it easier to pull them into the Civitai Comfy Nodes.','在资源上显示Civitai AIR,以便更容易地将它们拉入Civitai Comfy Nodes.'],
    ['Model Card V2','模型卡片 V2'],
    ['A fresh style for model cards with more information and a better layout.','模型卡片的新风格,提供更多信息和更好的布局。'],
    ['New @mentions','新的@提及'],
    ['Model download milestones','模型下载里程碑'],
    ['Model like milestones','模型点赞里程碑'],
    ['New versions of liked models','已点赞模型的新版本'],
    ['New models from followed users','关注用户的新模型'],
    ['New reviews','新评论'],
    ['Review reminders','评论提醒'],
    ['New comments on your models','您的模型的新评论'],
    ['New comment responses','新的评论回复'],
    ['New responses to comments and reviews on your models','对您的模型的评论和评价的新回应'],
    ['New replies to comment threads you are in','您所在的评论线程的新回复'],
    ['New review responses','新的评价回应'],
    ['New comments on your images','您的图片的新评论'],
    ['New comments on your articles','您的文章的新评论'],
    ['Comment reaction milestones','评论反应里程碑'],
    ['Image reaction milestones','图片反应里程碑'],
    ['Article reaction milestones','文章反应里程碑'],
    ['New Civitai features','新的Civitai特性'],
    ['Article view milestones','文章查看里程碑'],
    ['Article like milestones','文章点赞里程碑'],
    ['New articles from followed users','关注用户的新文章'],
    ['Notifications Settings', '通知设置'],
    ['Email Notifications', '邮件通知'],
    ['Newsletter', '通讯'],

    ['Manage Account', '管理帐户'],
    ['Profile', '配置文件'],
    ['Newsletter', '通讯'],

    //内容审查
    ['Content Moderation','内容审查'],
    ['Hidden Tags','隐藏标签'],
    ['Hidden Users','隐藏用户'],
    ['Mature Content','成人内容'],
    ['Explicit Adult Content','明确的成人内容'],
    ['Suggestive Content','暗示性内容'],
    ['Violence','暴力'],
    ['Visually Disturbing','视觉上令人不安的内容'],
    ['Offensive Gestures','冒犯性的手势'],
    ['Toggle all that you are comfortable seeing','启用内容'],

    ['Connected Accounts','链接账号'],
    ['API Keys','API密钥'],
    //删号
    ['Delete account','删除账号'],
    ['Delete your account','以上内容我都没读,删号,开润'],

    // 其他
    ['Featured','特色'],

    //模型页
    ['Download','下载'],
    ['Like','我超爱'],
    ['Share','分享'],

    ['Details','详情'],
    ['Base 模式l','底模'],
    ['Type','类型'],
    ['Downloads','下载量'],
    ['Uploaded','上传时间'],
    ['Updated','更新'],
    ['Hash','哈希'],

    ['Add Review','添加评论'],
    ['Reviews','评论'],
    ['See Reviews','查看评论'],
    ['Hash','哈希'],
    ['Hash','哈希'],

    ['File','文件'],
    ['Verified','验证于'],
    ['About this version','版本信息'],
    ['Discussion','讨论'],
    ['Add Comment','讲俩句'],
    ['Gallery','画廊'],
    ['Add Post','发表文章'],
    ['Create Image Post','发表图片帖'],


      // 月份
      ['Jan', '1月'],
      ['Feb', '2月'],
      ['Mar', '3月'],
      ['Apr', '4月'],
      ['May', '5月'],
      ['Jun', '6月'],
      ['Jul', '7月'],
      ['Aug', '8月'],
      ['Sep', '9月'],
      ['Oct', '10月'],
      ['Nov', '11月'],
      ['Dec', '12月'],
      // 时间
      ['hours ago', '小时前'],
      ['an hour ago', '1小时前'],
      ['a few seconds ago', '几秒钟前'],
      ['minutes ago', '分钟前'],
      ['days ago', '天前'],
      ['a day ago', '1天前'],

      //优先级最低
      ['Settings', '设置'],
      ['all','所有'],
      // 新增功能
      ['New homepage!', '新主页!'],
      ['Home', '家'],
      ['Announcements', '公告'],
      ['Connect','连接'],
      ['Remove','重置'],
      ['All','全部'],
      ['character','角色'],
      ['style','风格'],
      ['celebrity','名人'],
      ['concept','概念'],
      ['base model','基础模型'],
      ['clothing','服装'],
      ['poses','姿势'],
      ['background','背景'],
      ['vehicle','交通工具'],
      ['buildings','建筑物'],
      ['tool','工具'],
      ['objects','物体'],
      ['animal','动物'],
      ['action','动作'],
      ['assets','资产'],

  ])

  replaceText(document.body)
  const bodyObserver = new MutationObserver(mutations => {
    mutations.forEach(mutation => {
      mutation.addedNodes.forEach(addedNode => replaceText(addedNode))
    })
  })
  bodyObserver.observe(document.body, { childList: true, subtree: true })

  function replaceText(node) {
    nodeForEach(node).forEach(htmlnode => {
      i18n.forEach((value, index) => {
        const textReg = new RegExp(index, 'g')
        if (htmlnode instanceof Text && htmlnode.nodeValue.includes(index))
          htmlnode.nodeValue = htmlnode.nodeValue.replace(textReg, value)
        else if (htmlnode instanceof HTMLInputElement && htmlnode.value.includes(index))
          htmlnode.value = htmlnode.value.replace(textReg, value)
      })
    })
  }

  function nodeForEach(node) {
    const list = []
    if (node.childNodes.length === 0) list.push(node)
    else {
      node.childNodes.forEach(child => {
        if (child.childNodes.length === 0) list.push(child)
        else list.push(...nodeForEach(child))
      })
    }
    return list
  }

  function fetchContent(url, callback) {
    GM_xmlhttpRequest({
      method: "GET",
      url: url,
      onload: function(response) {
        if (response.status === 200) {
          callback(response.responseText);
        }
      }
    });
  }
})();