跳转到内容

仪表板自定义

Lunaria 提供了多种方式来自定义您的本地化仪表板,使其更贴合您项目的外观和感觉。请遵循本指南,了解所有可用的自定义选项。

标题和描述

默认情况下,Lunaria 会为您的仪表板添加默认标题和描述。您可以更改它们,以便通过搜索引擎轻松识别和找到您项目中的仪表板。

  1. 在您的 Lunaria 配置中添加 dashboard.title 选项。所定义的标题也会显示在仪表板的标题栏中:

    lunaria.config.json
    {
    "dashboard": {
    "title": "Lunaria 本地化状态"
    }
    }
  2. 在您的 Lunaria 配置中添加 dashboard.description 选项:

    lunaria.config.json
    {
    "dashboard": {
    "title": "Lunaria 本地化状态",
    "description": "Lunaria 项目的本地化状态仪表板。"
    }
    }

规范网址

如果您希望发布仪表板的不同版本(例如仪表板本身的本地化版本),设置 规范网址 可以帮助优化您的仪表板在搜索引擎中的排名。

要添加规范网址,您可以在 Lunaria 配置文件中设置 dashboard.site

lunaria.config.json
{
"dashboard": {
"site": "https://localization.lunaria.dev/"
}
}

图标

设置图标有助于匹配您项目的整体风格,并使用户在浏览器中更容易识别您的仪表板。Lunaria 允许您定义多个外部图标和一个内联图标。

要添加图标,您必须在 Lunaria 配置中设置 dashboard.favicon,并指定 externalinline 属性之一或两者。

外部图标

外部图标是从其他 URL 加载的资源。您可以在 dashboard.faviconexternal 属性中添加它们。以下示例同时添加了 .svg.ico 图标。

lunaria.config.json
{
"dashboard": {
"favicon": {
"external": [
{
"link": "https://lunaria.dev/favicon.svg",
"type": "image/svg+xml"
},
{
"link": "https://lunaria.dev/favicon.ico",
"type": "image/x-icon"
},
]
}
}
}

内联图标

内联图标是通过数据统一资源标识符(Data URI)附加到仪表板的本地 .svg 图标。您可以通过 dashboard.faviconinline 属性添加一个。

  1. 将您的图标 SVG 文件添加到项目中的某个目录(例如 src/assets/):

    • 文件夹src/
      • 文件夹assets/
        • favicon.svg
    • lunaria.config.json
  2. 在您的 Lunaria 配置中,将图标路径作为 dashboard.faviconinline 属性添加:

    lunaria.config.json
    {
    "dashboard": {
    "favicon": {
    "inline": "./src/assets/favicon.svg"
    }
    }
    }

隐藏路径前缀

仪表板包含多个指向源代码和本地化内容的路径链接。这些路径可能非常长,具体取决于它们距离项目根目录有多远。例如,如果您的内容文件路径的唯一部分仅从 src/content/docs/ 开始,您可能希望隐藏这一段路径,仅显示相关内容,例如 guides/my-content.mdx

为此,您可以在 Lunaria 配置中设置 dashboard.basesToHide 选项,列出所有要隐藏的路径前缀。本示例假设您正在跟踪位于 src/content/docs/src/i18n/ 的内容文件:

lunaria.config.json
{
"dashboard": {
"basesToHide": ["src/content/docs/", "src/i18n/"]
}
}

启用后,src/content/docs/guide.mdxsrc/i18n/dictionary.ts 等路径引用将被缩短为其唯一部分,即 guide.mdxdictionary.ts

自定义 CSS

您可以通过添加自己的自定义 CSS 来进一步定制仪表板,从而修改或扩展 Lunaria 默认提供的样式。

  1. 在项目中的某个目录(例如 src/styles/)添加一个 CSS 文件。例如,您可以更改默认的正文字体族:

    src/styles/lunaria.css
    :root {
    --ln-font-body: Tahoma, sans-serif;
    }
  2. 将您的 CSS 文件路径添加到 Lunaria 配置的 dashboard.customCss 数组属性中:

    lunaria.config.json
    {
    "dashboard": {
    "customCss": ["./src/styles/lunaria.css"]
    }
    }

自定义标签和语言

默认情况下,Lunaria 仪表板的 UI 标签使用英文编写。这些 UI 标签可以完全更改,无论是简单的文本标签、语言值还是动态句子(例如“已完成 X 项,过时 X 项,缺失 X 项”)。

文本标签

例如,您可以更改当某语言的本地化完成率达到 100% 时显示的默认消息,只需更改 dashboard.uistatusByLocale.completeLocalization 属性:

lunaria.config.json
{
"dashboard": {
"ui": {
"statusByLocale.completeLocalization": "未发现缺失或过时的更改,祝贺!"
}
}
}

格式标签

一些名称中带有 Format 后缀的标签包含命名的 {} 占位符,这些占位符将动态替换为来自其他 UI 标签或内部上下文的值,例如:

"statusByLocale.detailsTitleFormat": "{locale_name} ({locale_tag})",

这些也可以更改,但强烈建议不要删除默认存在的任何 {} 占位符,否则可能会导致预期的动态值未被插入。

例如,您可以通过对默认 statusByLocale.detailsTitleFormat 值进行小改动,将语言详情摘要格式从 Deutsch (de) 改为 Deutsch - de

lunaria.config.json
{
"dashboard": {
"ui": {
"statusByLocale.detailsTitleFormat": "{locale_name} - {locale_tag}",
}
}
}

langdir

由于所有标签都可以更改,因此无需完全将仪表板翻译成另一种语言。为了使这一过程更加简单,dashboard.ui 暴露了 langdir 属性,它们直接映射到仪表板中使用的 HTML langdir 属性。

例如,以下是将仪表板语言更改为巴西葡萄牙语的方法(为简洁起见,省略了许多属性):

lunaria.config.json
{
"dashboard": {
"ui": {
"lang": "pt-BR",
"statusByFile.heading": "按文件的本地化状态",
"statusByFile.tableRowFile": "文件",
}
}
}

自定义 UI 元素

Lunaria 仪表板的设计具有高度灵活性,可通过 自定义 CSS 和可用的 配置选项 进行轻松自定义。当这些还不够时,Lunaria 还允许您使用其 渲染器 API 扩展和覆盖仪表板的 UI。

  1. 在项目中添加一个新的 renderer.config.tsrenderer.config.js 文件,内容如下:

    renderer.config.ts
    import { defineRendererConfig } from '@lunariajs/core';
    export default defineRendererConfig({
    // 选项将放在此处...
    });
  2. 将您的渲染器文件路径添加到 Lunaria 配置的 renderer 配置属性中:

    lunaria.config.json
    {
    "renderer": "./renderer.config.ts"
    }

自定义组件

Lunaria 中的所有 UI 元素都是使用原生的 HTML 构建的,不依赖任何框架。为了改善编写体验,Lunaria 提供了一个内置的 html 标签模板,帮助您构建自己的组件。

在 Lunaria 中,组件是一个接收若干参数并返回一段 HTML 字符串的函数:

example-component.ts
import { html } from '@lunariajs/core';
const CustomParagraph = () => html`<p>这是我的自定义段落组件!</p>`;

由于这些组件是 模板字面量,您可以像在 JavaScript 中一样使用 ${} 语法插入值:

interpolating-value.ts
import { html } from '@lunariajs/core';
const favoriteColor = "red";
const ColorComponent = () => html`<p>我最喜欢的颜色是 ${favoriteColor}!</p>`.
查看生成的 HTML
<p>我最喜欢的颜色是 red!</p>

您还可以使用 .map() 方法对值列表(例如数组)进行插值:

interpolating-list.ts
import { html } from '@lunariajs/core';
const catColors = ["grey", "white", "black", "orange", "buff"];
const CatColorsList = () => html`<ul>${catColors.map((catColor) => html`<li>${catColor}</li>`)}</ul>`
查看生成的 HTML
<ul>
<li>grey</li>
<li>white</li>
<li>black</li>
<li>orange</li>
<li>buff</li>
</ul>

插槽元素

元素可以通过 渲染器的 slots 属性 被插入到仪表板中。所有组件都会收到一份您的 Lunaria 配置副本,您可以用来获取值:

  1. 使用 html 标签模板创建新组件。本例中,创建一个名为 "robots" 元标签,其内容为 "noindex",以避免搜索引擎索引仪表板:

    renderer.config.ts
    import { defineRendererConfig, html } from '@lunariajs/core';
    const NoIndex = () => html`<meta name="robots" content="noindex" />`;
    export default defineRendererConfig({});
  2. 将创建的组件添加到 slots 属性 中的一个可用插槽。此处使用 head 插槽,将组件插入仪表板的 <head> 元素 中:

    renderer.config.ts
    import { defineRendererConfig, html } from '@lunariajs/core';
    const NoIndex = () => html`<meta name="robots" content="noindex" />`;
    export default defineRendererConfig({
    slots: {
    head: NoIndex,
    }
    });

覆盖元素

元素也可以通过 渲染器的 overrides 属性 在仪表板中被覆盖。添加到 overrides 中的所有组件都会收到一份您的 Lunaria 配置副本,以及生成的 Lunaria 状态(meta 属性除外),您可从中获取值:

  1. 使用 html 标签模板创建新组件。本例中,组件将覆盖仪表板的主体,并显示每个本地化内容的 sharedPath

    renderer.config.ts
    import { defineRendererConfig, html } from '@lunariajs/core';
    const NewBody = (config, status) => html`<ul>${status.map((s) => html`<li>${s.sharedPath}</li>`)}</ul>`;
    export default defineRendererConfig({});
  2. 将创建的组件添加到 overrides 属性 中的一个可用覆盖项。此处使用 body 插槽,将组件插入并覆盖仪表板的 <body> 元素 内的所有内容:

    renderer.config.ts
    import { defineRendererConfig, html } from '@lunariajs/core';
    const NewBody = (config, status) => html`<ul>${status.map((s) => html`<li>${s.sharedPath}</li>`)}</ul>`;
    export default defineRendererConfig({
    overrides: {
    body: NewBody,
    }
    });