-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[I18n] Support interpreting individual i18n-values as html or text-only #26274
[I18n] Support interpreting individual i18n-values as html or text-only #26274
Conversation
Pinging @elastic/kibana-platform |
Out of curiosity, why did we decide against flagging html/text per-variable? Saying all variables are html or not seems like something that would be easy to miss if someone comes in down the road and adds another variable. |
💚 Build Succeeded |
💚 Build Succeeded |
Based on our recent discussions here is the PoC that seems to work as we expect. As it's perf critical code I tried to be as "lazy" in costly operations as possible. import { IDirective, IRootElementService, IScope } from 'angular';
import { I18nServiceType } from './provider';
interface I18nScope extends IScope {
values?: Record<string, any>;
defaultMessage: string;
id: string;
}
const HTML_KEY_PREFIX = 'html_';
const PLACEHOLDER_SEPARATOR = '@I18N@';
export function i18nDirective(
i18n: I18nServiceType,
$sanitize: (html: string) => string
): IDirective<I18nScope> {
return {
restrict: 'A',
scope: {
id: '@i18nId',
defaultMessage: '@i18nDefaultMessage',
values: '<?i18nValues',
},
link($scope, $element) {
if ($scope.values) {
$scope.$watchCollection('values', () => setContent($element, $scope, $sanitize, i18n));
} else {
setContent($element, $scope, $sanitize, i18n);
}
},
};
}
function setContent(
$element: IRootElementService,
$scope: I18nScope,
$sanitize: (html: string) => string,
i18n: I18nServiceType
) {
const originalValues = $scope.values;
const valuesWithPlaceholders = {} as Record<string, any>;
let hasValuesWithPlaceholders = false;
// If we have values with keys starts with HTML_KEY_PREFIX we should replace
// them with special placeholders that later one will be inserted as HTML
// into the DOM, the rest of the content will be treated as text. We don't
// sanitize values at this stage as some of the values can be excluded from
// the translated string (e.g. not used by ICU conditional statements).
if (originalValues) {
for (const [key, value] of Object.entries(originalValues)) {
if (key.startsWith(HTML_KEY_PREFIX)) {
valuesWithPlaceholders[
key.slice(HTML_KEY_PREFIX.length)
] = `${PLACEHOLDER_SEPARATOR}${key}${PLACEHOLDER_SEPARATOR}`;
hasValuesWithPlaceholders = true;
} else {
valuesWithPlaceholders[key] = value;
}
}
}
const label = i18n($scope.id, {
values: valuesWithPlaceholders,
defaultMessage: $scope.defaultMessage,
});
// If there are no placeholders to replace treat everything as text, otherwise
// insert label piece by piece replacing every placeholder with corresponding
// sanitized HTML content.
if (!hasValuesWithPlaceholders) {
$element.text(label);
} else {
$element.empty();
for (const contentOrPlaceholder of label.split(PLACEHOLDER_SEPARATOR)) {
if (!contentOrPlaceholder) {
continue;
}
$element.append(
originalValues!.hasOwnProperty(contentOrPlaceholder)
? $sanitize(originalValues![contentOrPlaceholder])
: document.createTextNode(contentOrPlaceholder)
);
}
}
} @LeanidShutau would you mind proof reading this and take it as a base for your PR if you think it works as we expect? |
4641dbb
to
aed376a
Compare
💚 Build Succeeded |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, just a couple of nits! Also would you mind adding this html_
thing into i18n Angular docs/guideline?
Please, wait for feedback from @spalger before merging this as well. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Is there a documentation update we should make along with this? |
💚 Build Succeeded |
💚 Build Succeeded |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
…ly (elastic#26274) * [I18n] Add attribute for interpreting i18n-values as html or text-only * Switch over to html_ prefixed values solution * Update readme
6.x/6.6: f1f5f1c |
Resolves #26173