i18n: Initialize FormatJS.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg
2021-04-09 18:11:59 -07:00
committed by Tim Abbott
parent 6cf398f157
commit 4b4cea90a3
7 changed files with 518 additions and 37 deletions

View File

@@ -9,9 +9,13 @@ const {page_params} = require("../zjsunit/zpage_params");
// We download our translations in `page_params` (which
// are for the user's chosen language), so we simulate
// that here for the tests.
page_params.default_language = "en";
page_params.translation_data = {
"Quote and reply or forward": "French translation",
"Notification triggers": "Some French text",
"Quote and reply or forward": "Citer et répondre ou transférer",
"Notification triggers": "Déclencheurs de notification",
"You subscribed to stream {stream}": "Vous n'êtes pas abonnés au canal {stream}",
"<p>The stream <b>{stream_name}</b> does not exist.</p><p>Manage your subscriptions <z-link>on your Streams page</z-link>.</p>":
"<p>Le canal <b>{stream_name}</b> n'existe pas.</p><p>Gérez vos abonnements <z-link>sur votre page canaux</z-link>.</p>",
};
// All of our other tests stub out i18n activity;
@@ -20,9 +24,46 @@ page_params.translation_data = {
// to set `i18n` to `i18next` on the global namespace
// for `templates.js`.
unmock_module("../../static/js/i18n");
zrequire("i18n");
const {$t, $t_html} = zrequire("i18n");
zrequire("templates");
run_test("$t", () => {
// Normally the id would be provided by babel-plugin-formatjs, but
// this test file is not processed by Babel.
assert.equal(
$t({id: "Quote and reply or forward", defaultMessage: "Quote and reply or forward"}),
"Citer et répondre ou transférer",
);
assert.equal(
$t(
{
id: "You subscribed to stream {stream}",
defaultMessage: "You subscribed to stream {stream}",
},
{stream: "l'abonnement"},
),
"Vous n'êtes pas abonnés au canal l'abonnement",
);
});
run_test("$tr", () => {
assert.equal(
$t_html(
{
id:
"<p>The stream <b>{stream_name}</b> does not exist.</p><p>Manage your subscriptions <z-link>on your Streams page</z-link>.</p>",
defaultMessage:
"<p>The stream <b>{stream_name}</b> does not exist.</p><p>Manage your subscriptions <z-link>on your Streams page</z-link>.</p>",
},
{
stream_name: "l'abonnement",
"z-link": (content_html) => `<a href='#streams/all'>${content_html}</a>`,
},
),
"<p>Le canal <b>l&#39;abonnement</b> n'existe pas.</p><p>Gérez vos abonnements <a href='#streams/all'>sur votre page canaux</a>.</p>",
);
});
run_test("t_tag", () => {
const args = {
message: {
@@ -40,7 +81,7 @@ run_test("t_tag", () => {
};
const html = require("../../static/templates/actions_popover_content.hbs")(args);
assert(html.indexOf("French translation") > 0);
assert(html.indexOf("Citer et répondre ou transférer") > 0);
});
run_test("tr_tag", () => {
@@ -64,5 +105,5 @@ run_test("tr_tag", () => {
};
const html = require("../../static/templates/settings_tab.hbs")(args);
assert(html.indexOf("Some French text") > 0);
assert(html.indexOf("Déclencheurs de notification") > 0);
});

View File

@@ -1,5 +1,59 @@
"use strict";
const {createIntl, createIntlCache} = require("@formatjs/intl");
const _ = require("lodash");
const cache = createIntlCache();
exports.intl = createIntl(
{
locale: "en",
defaultLocale: "en",
defaultRichTextElements: Object.fromEntries(
["b", "code", "em", "i", "kbd", "p", "strong"].map((tag) => [
tag,
(content_html) => `<${tag}>${content_html}</${tag}>`,
]),
),
},
cache,
);
exports.$t = (descriptor, values) =>
"translated: " +
exports.intl.formatMessage(
{
...descriptor,
id: `${descriptor.defaultMessage}#${descriptor.description}`,
},
values,
);
const default_html_elements = Object.fromEntries(
["b", "code", "em", "i", "kbd", "p", "strong"].map((tag) => [
tag,
(content_html) => `<${tag}>${content_html}</${tag}>`,
]),
);
exports.$t_html = (descriptor, values) =>
"translated HTML: " +
exports.intl.formatMessage(
{
...descriptor,
id: `${descriptor.defaultMessage}#${descriptor.description}`,
},
{
...default_html_elements,
...Object.fromEntries(
Object.entries(values ?? {}).map(([key, value]) => [
key,
typeof value === "function" ? value : _.escape(value),
]),
),
},
);
exports.i18n = {};
exports.i18n.t = function (str, context) {
// HAPPY PATH: most translations are a simple string: