feat(i18n): Arabic, Hebrew, Persian and Urdu, and a layout that mirrors; release v6.4.0
Four right-to-left languages at /ar/, /he/, /fa/ and /ur/ — thirteen in all. The layout no longer has a left and a right, it has a start and an end: the margins, insets and corners are CSS logical properties now, so they follow dir on <html>. Directional glyphs flip; keys, safety codes and session descriptors are pinned left-to-right so bidi cannot reorder what two people compare against each other's screens. Also fixed: the Service Worker was registered as './sw.js', which 404s from every locale subdirectory, so twelve of the thirteen pages had no worker at all. And the bundler ran before the dictionaries were generated, so a newly added language could reach the page ahead of the app that renders it.
This commit is contained in:
@@ -47,7 +47,7 @@ for (const code of site.locales) {
|
||||
const html = read(pageFor(code));
|
||||
const locale = localeFile(code);
|
||||
|
||||
assert.match(html, new RegExp(`<html lang="${locale.htmlLang}">`), `${code}: wrong <html lang>`);
|
||||
assert.match(html, new RegExp(`<html lang="${locale.htmlLang}" dir="${locale.dir}">`), `${code}: wrong <html lang>/<html dir>`);
|
||||
assert.ok(
|
||||
html.includes(`<link rel="canonical" href="${urlFor(code)}">`),
|
||||
`${code}: canonical must point at its own URL, not another locale's`
|
||||
@@ -181,7 +181,10 @@ for (const code of site.locales) {
|
||||
|
||||
const en = JSON.parse(read('locales/en.json'));
|
||||
const xx = JSON.parse(JSON.stringify(en));
|
||||
Object.assign(xx, { htmlLang: 'xx', ogLocale: 'xx_XX', nativeName: 'Test' });
|
||||
// Right-to-left on purpose: direction is carried from the locale file all the way
|
||||
// into <html dir> and the per-locale manifest, and the throwaway site is where that
|
||||
// plumbing can be exercised without a real RTL locale having to be the one under test.
|
||||
Object.assign(xx, { htmlLang: 'xx', ogLocale: 'xx_XX', nativeName: 'Test', dir: 'rtl' });
|
||||
xx.manifest = { name: 'XX name', short_name: 'XX', description: 'XX description' };
|
||||
writeFileSync(path.join(localesDir, 'en.json'), JSON.stringify(en, null, 2));
|
||||
writeFileSync(path.join(localesDir, 'xx.json'), JSON.stringify(xx, null, 2));
|
||||
@@ -202,7 +205,10 @@ for (const code of site.locales) {
|
||||
// The secondary locale points at itself, not at the default one.
|
||||
assert.ok(secondary.includes('<link rel="canonical" href="https://securebit.chat/xx/">'),
|
||||
'a secondary locale must be canonical to itself, or Google will not index it');
|
||||
assert.match(secondary, /<html lang="xx">/);
|
||||
assert.match(secondary, /<html lang="xx" dir="rtl">/,
|
||||
'the locale\'s writing direction must be on <html>, not applied later by the app');
|
||||
assert.match(primary, /<html lang="en" dir="ltr">/,
|
||||
'a left-to-right locale must still say so explicitly');
|
||||
|
||||
// hreflang has to be reciprocal: both pages list both locales plus x-default.
|
||||
for (const page of [primary, secondary]) {
|
||||
@@ -223,6 +229,7 @@ for (const code of site.locales) {
|
||||
assert.ok(secondary.includes('<link rel="manifest" href="/xx/manifest.json">'));
|
||||
const manifest = JSON.parse(at('xx/manifest.json'));
|
||||
assert.equal(manifest.lang, 'xx');
|
||||
assert.equal(manifest.dir, 'rtl', 'an installed RTL locale must launch right-to-left');
|
||||
assert.equal(manifest.start_url, '/xx/', 'an installed locale must launch into its own page');
|
||||
assert.equal(manifest.scope, '/', 'scope must still cover the whole site');
|
||||
assert.equal(manifest.name, 'XX name', 'manifest name should come from the locale file');
|
||||
|
||||
Reference in New Issue
Block a user