diff --git a/app/assets/javascripts/admin/addon/components/modal/reseed.hbs b/app/assets/javascripts/admin/addon/components/modal/reseed.hbs
index 46d26972f48..eb746b98ada 100644
--- a/app/assets/javascripts/admin/addon/components/modal/reseed.hbs
+++ b/app/assets/javascripts/admin/addon/components/modal/reseed.hbs
@@ -19,7 +19,7 @@
@type="checkbox"
@checked={{category.selected}}
/>
- {{category.name}}
+ {{category.displayName}}
{{/each}}
diff --git a/app/assets/javascripts/admin/addon/templates/site-settings.hbs b/app/assets/javascripts/admin/addon/templates/site-settings.hbs
index a8225709bf4..f264afee288 100644
--- a/app/assets/javascripts/admin/addon/templates/site-settings.hbs
+++ b/app/assets/javascripts/admin/addon/templates/site-settings.hbs
@@ -18,9 +18,9 @@
@route="adminSiteSettingsCategory"
@model={{category.nameKey}}
class={{category.nameKey}}
- title={{category.name}}
+ title={{category.displayName}}
>
- {{category.name}}
+ {{category.displayName}}
{{#if category.count}}
({{category.count}})
{{/if}}
diff --git a/app/assets/javascripts/discourse/app/components/categories-boxes-with-topics.hbs b/app/assets/javascripts/discourse/app/components/categories-boxes-with-topics.hbs
index c9ffc514d9b..5e0c8831124 100644
--- a/app/assets/javascripts/discourse/app/components/categories-boxes-with-topics.hbs
+++ b/app/assets/javascripts/discourse/app/components/categories-boxes-with-topics.hbs
@@ -19,7 +19,7 @@
{{#if c.read_restricted}}
{{d-icon this.lockIcon}}
{{/if}}
- {{c.name}}
+ {{c.displayName}}
diff --git a/app/assets/javascripts/discourse/app/components/categories-boxes.hbs b/app/assets/javascripts/discourse/app/components/categories-boxes.hbs
index d2a295d35ca..d5469e87332 100644
--- a/app/assets/javascripts/discourse/app/components/categories-boxes.hbs
+++ b/app/assets/javascripts/discourse/app/components/categories-boxes.hbs
@@ -29,7 +29,7 @@
{{#if c.read_restricted}}
{{d-icon this.lockIcon}}
{{/if}}
- {{c.name}}
+ {{c.displayName}}
diff --git a/app/assets/javascripts/discourse/app/components/category-title-link.hbs b/app/assets/javascripts/discourse/app/components/category-title-link.hbs
index b5c08397d42..1284bf33c59 100644
--- a/app/assets/javascripts/discourse/app/components/category-title-link.hbs
+++ b/app/assets/javascripts/discourse/app/components/category-title-link.hbs
@@ -4,7 +4,7 @@
{{#if this.category.read_restricted}}
{{d-icon this.lockIcon}}
{{/if}}
- {{dir-span this.category.name}}
+ {{dir-span this.category.displayName}}
{{#if this.category.uploaded_logo.url}}
diff --git a/app/assets/javascripts/discourse/app/helpers/category-link.js b/app/assets/javascripts/discourse/app/helpers/category-link.js
index 91df2ebb679..9b65a52e38b 100644
--- a/app/assets/javascripts/discourse/app/helpers/category-link.js
+++ b/app/assets/javascripts/discourse/app/helpers/category-link.js
@@ -112,7 +112,7 @@ function buildTopicCount(count) {
}
export function defaultCategoryLinkRenderer(category, opts) {
- let descriptionText = escapeExpression(get(category, "description_text"));
+ let descriptionText = escapeExpression(get(category, "descriptionText"));
let restricted = get(category, "read_restricted");
let url = opts.url
? opts.url
@@ -156,7 +156,7 @@ export function defaultCategoryLinkRenderer(category, opts) {
${descriptionText ? 'title="' + descriptionText + '" ' : ""}
>`;
- let categoryName = escapeExpression(get(category, "name"));
+ let categoryName = escapeExpression(get(category, "displayName"));
if (siteSettings.support_mixed_text_direction) {
categoryDir = 'dir="auto"';
diff --git a/app/assets/javascripts/discourse/app/lib/plugin-api.gjs b/app/assets/javascripts/discourse/app/lib/plugin-api.gjs
index f800b02e0aa..83e3d21fb51 100644
--- a/app/assets/javascripts/discourse/app/lib/plugin-api.gjs
+++ b/app/assets/javascripts/discourse/app/lib/plugin-api.gjs
@@ -1537,8 +1537,8 @@ class PluginApi {
* displayName: "bugs"
* href: "/c/bugs",
* init: (navItem, category) => { if (category) { navItem.set("category", category) } }
- * customFilter: (category, args, router) => { return category && category.name !== 'bug' }
- * customHref: (category, args, router) => { if (category && category.name) === 'not-a-bug') return "/a-feature"; },
+ * customFilter: (category, args, router) => { return category && category.displayName !== 'bug' }
+ * customHref: (category, args, router) => { if (category && category.displayName) === 'not-a-bug') return "/a-feature"; },
* before: "top",
* forceActive: (category, args, router) => router.currentURL === "/a/b/c/d",
* })
diff --git a/app/assets/javascripts/discourse/app/lib/sidebar/user/categories-section/category-section-link.js b/app/assets/javascripts/discourse/app/lib/sidebar/user/categories-section/category-section-link.js
index cd350e8b7c8..d14bd6de981 100644
--- a/app/assets/javascripts/discourse/app/lib/sidebar/user/categories-section/category-section-link.js
+++ b/app/assets/javascripts/discourse/app/lib/sidebar/user/categories-section/category-section-link.js
@@ -178,11 +178,11 @@ export default class CategorySectionLink {
}
get title() {
- return this.category.description_text;
+ return this.category.descriptionText;
}
get text() {
- return this.category.name;
+ return this.category.displayName;
}
get prefixType() {
diff --git a/app/assets/javascripts/discourse/app/lib/transformer/registry.js b/app/assets/javascripts/discourse/app/lib/transformer/registry.js
index 1f6ea052df3..f111349d31a 100644
--- a/app/assets/javascripts/discourse/app/lib/transformer/registry.js
+++ b/app/assets/javascripts/discourse/app/lib/transformer/registry.js
@@ -5,6 +5,8 @@ export const BEHAVIOR_TRANSFORMERS = Object.freeze([
export const VALUE_TRANSFORMERS = Object.freeze([
// use only lowercase names
+ "category-description-text",
+ "category-display-name",
"header-notifications-avatar-size",
"home-logo-href",
"home-logo-image-url",
diff --git a/app/assets/javascripts/discourse/app/models/category.js b/app/assets/javascripts/discourse/app/models/category.js
index 44080ed62f7..a6cf7a908d6 100644
--- a/app/assets/javascripts/discourse/app/models/category.js
+++ b/app/assets/javascripts/discourse/app/models/category.js
@@ -3,6 +3,7 @@ import { computed, get } from "@ember/object";
import { service } from "@ember/service";
import { ajax } from "discourse/lib/ajax";
import { NotificationLevels } from "discourse/lib/notification-levels";
+import { applyValueTransformer } from "discourse/lib/transformer";
import PermissionType from "discourse/models/permission-type";
import RestModel from "discourse/models/rest";
import Site from "discourse/models/site";
@@ -475,6 +476,22 @@ export default class Category extends RestModel {
}
}
+ get descriptionText() {
+ return applyValueTransformer(
+ "category-description-text",
+ this.get("description_text"),
+ {
+ category: this,
+ }
+ );
+ }
+
+ get displayName() {
+ return applyValueTransformer("category-display-name", this.get("name"), {
+ category: this,
+ });
+ }
+
@computed("parent_category_id", "site.categories.[]")
get parentCategory() {
if (this.parent_category_id) {
diff --git a/app/assets/javascripts/discourse/app/routes/build-category-route.js b/app/assets/javascripts/discourse/app/routes/build-category-route.js
index 678f7027534..f4a83abcf6d 100644
--- a/app/assets/javascripts/discourse/app/routes/build-category-route.js
+++ b/app/assets/javascripts/discourse/app/routes/build-category-route.js
@@ -117,11 +117,11 @@ class AbstractCategoryRoute extends DiscourseRoute {
"filters." + this.filter(category).replace("/", ".") + ".title"
);
- let categoryName = category.name;
+ let categoryName = category.displayName;
if (category.parent_category_id) {
const list = Category.list();
const parentCategory = list.findBy("id", category.parent_category_id);
- categoryName = `${parentCategory.name}/${categoryName}`;
+ categoryName = `${parentCategory.displayName}/${categoryName}`;
}
return I18n.t("filters.with_category", {
diff --git a/app/assets/javascripts/discourse/app/routes/tag-show.js b/app/assets/javascripts/discourse/app/routes/tag-show.js
index c01eb9aa96a..fbd7ae19c68 100644
--- a/app/assets/javascripts/discourse/app/routes/tag-show.js
+++ b/app/assets/javascripts/discourse/app/routes/tag-show.js
@@ -179,7 +179,7 @@ export default class TagShowRoute extends DiscourseRoute {
return I18n.t("tagging.filters.with_category", {
filter: filterText,
tag: model.tag.id,
- category: model.category.name,
+ category: model.category.displayName,
});
} else {
return I18n.t("tagging.filters.without_category", {
@@ -191,7 +191,7 @@ export default class TagShowRoute extends DiscourseRoute {
if (model.category) {
return I18n.t("tagging.filters.untagged_with_category", {
filter: filterText,
- category: model.category.name,
+ category: model.category.displayName,
});
} else {
return I18n.t("tagging.filters.untagged_without_category", {
diff --git a/app/assets/javascripts/discourse/app/static/wizard/components/fields/image-previews/logo-small.js b/app/assets/javascripts/discourse/app/static/wizard/components/fields/image-previews/logo-small.js
index 18f271481fb..f33e49318c0 100644
--- a/app/assets/javascripts/discourse/app/static/wizard/components/fields/image-previews/logo-small.js
+++ b/app/assets/javascripts/discourse/app/static/wizard/components/fields/image-previews/logo-small.js
@@ -73,7 +73,7 @@ export default PreviewBaseComponent.extend({
ctx.font = `Bold ${badgeSize * 1.2}px '${font}'`;
ctx.fillStyle = colors.primary;
ctx.fillText(
- category.name,
+ category.displayName,
afterLogo + badgeSize * 1.5,
headerHeight * 0.7 + badgeSize * 0.9
);
diff --git a/app/assets/javascripts/discourse/app/static/wizard/components/fields/styling-preview/-homepage-preview.js b/app/assets/javascripts/discourse/app/static/wizard/components/fields/styling-preview/-homepage-preview.js
index bb94e4c5930..d4a49e8dcd4 100644
--- a/app/assets/javascripts/discourse/app/static/wizard/components/fields/styling-preview/-homepage-preview.js
+++ b/app/assets/javascripts/discourse/app/static/wizard/components/fields/styling-preview/-homepage-preview.js
@@ -85,7 +85,11 @@ export default PreviewBaseComponent.extend({
ctx.font = `Bold ${bodyFontSize * 1.3}em '${font}'`;
ctx.fillStyle = colors.primary;
ctx.textAlign = "center";
- ctx.fillText(category.name, boxStartX + boxWidth / 2, boxStartY + 25);
+ ctx.fillText(
+ category.displayName,
+ boxStartX + boxWidth / 2,
+ boxStartY + 25
+ );
ctx.textAlign = "left";
if (opts.topics) {
@@ -167,7 +171,7 @@ export default PreviewBaseComponent.extend({
const textPos = y + categoryHeight * 0.35;
ctx.font = `Bold ${bodyFontSize * 1.1}em '${font}'`;
ctx.fillStyle = colors.primary;
- ctx.fillText(category.name, cols[0], textPos);
+ ctx.fillText(category.displayName, cols[0], textPos);
ctx.font = `${bodyFontSize * 0.8}em '${font}'`;
ctx.fillStyle = textColor;
@@ -263,7 +267,7 @@ export default PreviewBaseComponent.extend({
const textPos = y + categoryHeight * 0.35;
ctx.font = `Bold ${bodyFontSize * 1.1}em '${font}'`;
ctx.fillStyle = colors.primary;
- ctx.fillText(category.name, cols[0], textPos);
+ ctx.fillText(category.displayName, cols[0], textPos);
ctx.font = `${bodyFontSize * 0.8}em '${font}'`;
ctx.fillStyle = textColor;
@@ -328,7 +332,7 @@ export default PreviewBaseComponent.extend({
ctx.fillStyle = colors.primary;
ctx.fillText(
- category.name,
+ category.displayName,
cols[3] + badgeSize * 3,
y + topicHeight * 0.76
);
@@ -409,7 +413,7 @@ export default PreviewBaseComponent.extend({
ctx.fillStyle = colors.primary;
ctx.fillText(
- category.name,
+ category.displayName,
cols[0] + badgeSize * 2,
y + rowHeight * 0.73
);
diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js
index 161af3e3be8..727be141555 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-plugin-api-test.js
@@ -543,9 +543,9 @@ acceptance("Sidebar - Plugin API", function (needs) {
route: "discovery.latestCategory",
routeQuery: { status: "open" },
shouldRegister: ({ category }) => {
- if (category.name === category1.name) {
+ if (category.displayName === category1.displayName) {
return true;
- } else if (category.name === category2.name) {
+ } else if (category.displayName === category2.displayName) {
return false;
}
},
diff --git a/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-categories-section-test.js b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-categories-section-test.js
index d50d6032d19..ba24ce52761 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-categories-section-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/sidebar-user-categories-section-test.js
@@ -177,7 +177,7 @@ acceptance("Sidebar - Logged on user - Categories Section", function (needs) {
exists(
`.sidebar-section-link-wrapper[data-category-id=${category.id}]`
),
- `${category.name} section link is shown`
+ `${category.displayName} section link is shown`
);
});
});
@@ -677,7 +677,7 @@ acceptance("Sidebar - Logged on user - Categories Section", function (needs) {
query(
`.sidebar-section-link-wrapper[data-category-id="${category.id}"] a`
).title,
- category.description_text,
+ category.descriptionText,
"category description without HTML entity is used as the link's title"
);
});
diff --git a/app/assets/javascripts/discourse/tests/acceptance/transformers/category-description-text-test.js b/app/assets/javascripts/discourse/tests/acceptance/transformers/category-description-text-test.js
new file mode 100644
index 00000000000..9a447fdc215
--- /dev/null
+++ b/app/assets/javascripts/discourse/tests/acceptance/transformers/category-description-text-test.js
@@ -0,0 +1,26 @@
+import { visit } from "@ember/test-helpers";
+import { test } from "qunit";
+import { withPluginApi } from "discourse/lib/plugin-api";
+import { acceptance } from "discourse/tests/helpers/qunit-helpers";
+
+acceptance("category-description-text transformer", function () {
+ test("applying a value transformation", async function (assert) {
+ withPluginApi("1.34.0", (api) => {
+ api.registerValueTransformer(
+ "category-description-text",
+ ({ value, context }) =>
+ value[0] + "-" + context.category.id + "-transformed"
+ );
+ });
+
+ await visit("/");
+
+ assert
+ .dom("[data-topic-id='11994'] .badge-category")
+ .hasAttribute(
+ "title",
+ "A-1-transformed",
+ "it transforms the category description text"
+ );
+ });
+});
diff --git a/app/assets/javascripts/discourse/tests/acceptance/transformers/category-display-name-test.js b/app/assets/javascripts/discourse/tests/acceptance/transformers/category-display-name-test.js
new file mode 100644
index 00000000000..df1f8634f61
--- /dev/null
+++ b/app/assets/javascripts/discourse/tests/acceptance/transformers/category-display-name-test.js
@@ -0,0 +1,25 @@
+import { visit } from "@ember/test-helpers";
+import { test } from "qunit";
+import { withPluginApi } from "discourse/lib/plugin-api";
+import { acceptance } from "discourse/tests/helpers/qunit-helpers";
+
+acceptance("category-display-name transformer", function () {
+ test("applying a value transformation", async function (assert) {
+ withPluginApi("1.34.0", (api) => {
+ api.registerValueTransformer(
+ "category-display-name",
+ ({ value, context }) =>
+ value + "-" + context.category.id + "-transformed"
+ );
+ });
+
+ await visit("/");
+
+ assert
+ .dom("[data-topic-id='11997'] .badge-category__name")
+ .hasText(
+ "feature-2-transformed",
+ "it transforms the category display name"
+ );
+ });
+});
diff --git a/app/assets/javascripts/discourse/tests/integration/helpers/category-badge-test.js b/app/assets/javascripts/discourse/tests/integration/helpers/category-badge-test.js
index bbeaba056f0..2ae920de031 100644
--- a/app/assets/javascripts/discourse/tests/integration/helpers/category-badge-test.js
+++ b/app/assets/javascripts/discourse/tests/integration/helpers/category-badge-test.js
@@ -15,7 +15,7 @@ module("Integration | Helper | category-badge", function (hooks) {
assert.strictEqual(
query(".badge-category__name").innerText.trim(),
- this.category.name
+ this.category.displayName
);
});
diff --git a/app/assets/javascripts/select-kit/addon/components/category-drop.js b/app/assets/javascripts/select-kit/addon/components/category-drop.js
index a5e1aa1cca7..703a5521280 100644
--- a/app/assets/javascripts/select-kit/addon/components/category-drop.js
+++ b/app/assets/javascripts/select-kit/addon/components/category-drop.js
@@ -152,7 +152,7 @@ export default ComboBoxComponent.extend({
return content;
},
- parentCategoryName: readOnly("selectKit.options.parentCategory.name"),
+ parentCategoryName: readOnly("selectKit.options.parentCategory.displayName"),
allCategoriesLabel: computed(
"parentCategoryName",
diff --git a/app/assets/javascripts/select-kit/addon/components/category-row.gjs b/app/assets/javascripts/select-kit/addon/components/category-row.gjs
index aa2a44c017f..d775d34fdb8 100644
--- a/app/assets/javascripts/select-kit/addon/components/category-row.gjs
+++ b/app/assets/javascripts/select-kit/addon/components/category-row.gjs
@@ -83,11 +83,11 @@ export default class CategoryRow extends Component {
}
get categoryName() {
- return this.category.name;
+ return this.category.displayName;
}
get categoryDescriptionText() {
- return this.category.description_text;
+ return this.category.descriptionText;
}
@cached