Portals can now override their name, page title and header text per locale, with a fallback chain of locale override → default locale → base value. Overrides are stored under portal.config.locale_translations and validated with a JSON schema. Editing is exposed as a "Localize content" action in each non-default locale's menu on the Locale page, and all public-facing portal views (classic + documentation layouts) render the localized values. The live chat widget is also loaded in the active portal locale. <img width="494" height="395" alt="Screenshot 2026-06-03 at 2 48 59 PM" src="https://github.com/user-attachments/assets/e55a06e8-f20f-4d8a-9352-92fde28a9a19" /> https://github.com/user-attachments/assets/f5affbd2-7ad4-415a-b376-57c759fc2aaa --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
114 lines
3.4 KiB
JavaScript
114 lines
3.4 KiB
JavaScript
import {
|
|
buildLocaleMenuItems,
|
|
buildPortalArticleURL,
|
|
buildPortalURL,
|
|
} from '../portalHelper';
|
|
|
|
describe('PortalHelper', () => {
|
|
describe('buildPortalURL', () => {
|
|
it('returns the correct url', () => {
|
|
window.chatwootConfig = {
|
|
hostURL: 'https://app.chatwoot.com',
|
|
helpCenterURL: 'https://help.chatwoot.com',
|
|
};
|
|
expect(buildPortalURL('handbook')).toEqual(
|
|
'https://help.chatwoot.com/hc/handbook'
|
|
);
|
|
window.chatwootConfig = {};
|
|
});
|
|
});
|
|
|
|
describe('buildPortalArticleURL', () => {
|
|
it('returns the correct url', () => {
|
|
window.chatwootConfig = {
|
|
hostURL: 'https://app.chatwoot.com',
|
|
helpCenterURL: 'https://help.chatwoot.com',
|
|
};
|
|
expect(
|
|
buildPortalArticleURL('handbook', 'culture', 'fr', 'article-slug')
|
|
).toEqual('https://help.chatwoot.com/hc/handbook/articles/article-slug');
|
|
window.chatwootConfig = {};
|
|
});
|
|
|
|
it('returns the correct url with custom domain', () => {
|
|
window.chatwootConfig = {
|
|
hostURL: 'https://app.chatwoot.com',
|
|
helpCenterURL: 'https://help.chatwoot.com',
|
|
};
|
|
expect(
|
|
buildPortalArticleURL(
|
|
'handbook',
|
|
'culture',
|
|
'fr',
|
|
'article-slug',
|
|
'custom-domain.dev'
|
|
)
|
|
).toEqual('https://custom-domain.dev/hc/handbook/articles/article-slug');
|
|
});
|
|
|
|
it('handles https in custom domain correctly', () => {
|
|
window.chatwootConfig = {
|
|
hostURL: 'https://app.chatwoot.com',
|
|
helpCenterURL: 'https://help.chatwoot.com',
|
|
};
|
|
expect(
|
|
buildPortalArticleURL(
|
|
'handbook',
|
|
'culture',
|
|
'fr',
|
|
'article-slug',
|
|
'https://custom-domain.dev'
|
|
)
|
|
).toEqual('https://custom-domain.dev/hc/handbook/articles/article-slug');
|
|
});
|
|
|
|
it('uses hostURL when helpCenterURL is not available', () => {
|
|
window.chatwootConfig = {
|
|
hostURL: 'https://app.chatwoot.com',
|
|
helpCenterURL: '',
|
|
};
|
|
expect(
|
|
buildPortalArticleURL('handbook', 'culture', 'fr', 'article-slug')
|
|
).toEqual('https://app.chatwoot.com/hc/handbook/articles/article-slug');
|
|
});
|
|
});
|
|
|
|
describe('buildLocaleMenuItems', () => {
|
|
it('disables other actions but keeps customize enabled for the default locale', () => {
|
|
const items = buildLocaleMenuItems({ isDefault: true, isDraft: false });
|
|
const customize = items.find(item => item.action === 'customize-content');
|
|
|
|
expect(customize).toBeTruthy();
|
|
expect(customize.disabled).toBeFalsy();
|
|
expect(
|
|
items
|
|
.filter(item => item.action !== 'customize-content')
|
|
.every(item => item.disabled)
|
|
).toBe(true);
|
|
});
|
|
|
|
it('returns publish, customize, and delete actions for draft locales', () => {
|
|
expect(
|
|
buildLocaleMenuItems({
|
|
isDefault: false,
|
|
isDraft: true,
|
|
}).map(({ action }) => action)
|
|
).toEqual(['publish-locale', 'customize-content', 'delete']);
|
|
});
|
|
|
|
it('returns default, draft, customize, and delete actions for live locales', () => {
|
|
expect(
|
|
buildLocaleMenuItems({
|
|
isDefault: false,
|
|
isDraft: false,
|
|
}).map(({ action }) => action)
|
|
).toEqual([
|
|
'change-default',
|
|
'move-to-draft',
|
|
'customize-content',
|
|
'delete',
|
|
]);
|
|
});
|
|
});
|
|
});
|