From 6ca4a0b324d8e51885362488acfc30af27db9105 Mon Sep 17 00:00:00 2001 From: Liam McLoughlin Date: Fri, 14 Aug 2020 14:54:06 +0100 Subject: [PATCH] Include locales in companion manifest Signed-off-by: Liam McLoughlin --- .../componentManifest.test.ts.snap | 28 +++++- src/componentManifest.ts | 89 +++++++++++-------- 2 files changed, 77 insertions(+), 40 deletions(-) diff --git a/src/__snapshots__/componentManifest.test.ts.snap b/src/__snapshots__/componentManifest.test.ts.snap index e991af4b..cde82cc5 100644 --- a/src/__snapshots__/componentManifest.test.ts.snap +++ b/src/__snapshots__/componentManifest.test.ts.snap @@ -80,6 +80,14 @@ Object { "companion": Object { "main": "companion/index.js", }, + "i18n": Object { + "en-us": Object { + "name": "My App", + }, + "fr-fr": Object { + "name": "Mon application", + }, + }, "manifestVersion": 2, "name": "My App", "requestedPermissions": Array [], @@ -107,6 +115,14 @@ Object { "main": "companion/index.js", }, "developerProfileId": "f00df00d-f00d-f00d-f00d-f00df00df00d", + "i18n": Object { + "en-us": Object { + "name": "My App", + }, + "fr-fr": Object { + "name": "Mon application", + }, + }, "manifestVersion": 2, "name": "My App", "requestedPermissions": Array [], @@ -122,6 +138,14 @@ Object { "companion": Object { "main": "companion/index.js", }, + "i18n": Object { + "en-us": Object { + "name": "My App", + }, + "fr-fr": Object { + "name": "Mon application", + }, + }, "manifestVersion": 2, "name": "My App", "requestedPermissions": Array [], @@ -224,9 +248,9 @@ Object { } `; -exports[`when there is a device entry point present when there are compiled language files ensures the default language en-US is the first key in the i18n object 1`] = `"{\\"appManifestVersion\\":1,\\"main\\":\\"device/index.js\\",\\"svgMain\\":\\"resources/index.view\\",\\"svgWidgets\\":\\"resources/widget.defs\\",\\"appType\\":\\"clockface\\",\\"apiVersion\\":\\"7.0.0\\",\\"buildId\\":\\"0x0f75775f470c1585\\",\\"bundleDate\\":\\"2018-06-27T00:00:00.000Z\\",\\"uuid\\":\\"b4ae822e-eca9-4fcb-8747-217f2a1f53a1\\",\\"name\\":\\"My App\\",\\"requestedPermissions\\":[],\\"supports\\":{\\"screenSize\\":{\\"w\\":300,\\"h\\":300}},\\"i18n\\":{\\"en-us\\":{\\"name\\":\\"My App\\",\\"resources\\":\\"lang/english\\"},\\"fr-fr\\":{\\"name\\":\\"Mon application\\"},\\"es-es\\":{\\"resources\\":\\"spanish/language\\"}}}"`; +exports[`when there is a device entry point present when there are compiled language files ensures the default language en-US is the first key in the i18n object 1`] = `"{\\"appManifestVersion\\":1,\\"main\\":\\"device/index.js\\",\\"svgMain\\":\\"resources/index.view\\",\\"svgWidgets\\":\\"resources/widget.defs\\",\\"appType\\":\\"clockface\\",\\"apiVersion\\":\\"7.0.0\\",\\"buildId\\":\\"0x0f75775f470c1585\\",\\"bundleDate\\":\\"2018-06-27T00:00:00.000Z\\",\\"uuid\\":\\"b4ae822e-eca9-4fcb-8747-217f2a1f53a1\\",\\"name\\":\\"My App\\",\\"requestedPermissions\\":[],\\"i18n\\":{\\"en-us\\":{\\"name\\":\\"My App\\",\\"resources\\":\\"lang/english\\"},\\"fr-fr\\":{\\"name\\":\\"Mon application\\"},\\"es-es\\":{\\"resources\\":\\"spanish/language\\"}},\\"supports\\":{\\"screenSize\\":{\\"w\\":300,\\"h\\":300}}}"`; -exports[`when there is a device entry point present when there are compiled language files ensures the default language es-ES is the first key in the i18n object 1`] = `"{\\"appManifestVersion\\":1,\\"main\\":\\"device/index.js\\",\\"svgMain\\":\\"resources/index.view\\",\\"svgWidgets\\":\\"resources/widget.defs\\",\\"appType\\":\\"clockface\\",\\"apiVersion\\":\\"7.0.0\\",\\"buildId\\":\\"0x0f75775f470c1585\\",\\"bundleDate\\":\\"2018-06-27T00:00:00.000Z\\",\\"uuid\\":\\"b4ae822e-eca9-4fcb-8747-217f2a1f53a1\\",\\"name\\":\\"My App\\",\\"requestedPermissions\\":[],\\"supports\\":{\\"screenSize\\":{\\"w\\":300,\\"h\\":300}},\\"i18n\\":{\\"es-es\\":{\\"resources\\":\\"spanish/language\\"},\\"en-us\\":{\\"name\\":\\"My App\\",\\"resources\\":\\"lang/english\\"},\\"fr-fr\\":{\\"name\\":\\"Mon application\\"}}}"`; +exports[`when there is a device entry point present when there are compiled language files ensures the default language es-ES is the first key in the i18n object 1`] = `"{\\"appManifestVersion\\":1,\\"main\\":\\"device/index.js\\",\\"svgMain\\":\\"resources/index.view\\",\\"svgWidgets\\":\\"resources/widget.defs\\",\\"appType\\":\\"clockface\\",\\"apiVersion\\":\\"7.0.0\\",\\"buildId\\":\\"0x0f75775f470c1585\\",\\"bundleDate\\":\\"2018-06-27T00:00:00.000Z\\",\\"uuid\\":\\"b4ae822e-eca9-4fcb-8747-217f2a1f53a1\\",\\"name\\":\\"My App\\",\\"requestedPermissions\\":[],\\"i18n\\":{\\"es-es\\":{\\"resources\\":\\"spanish/language\\"},\\"en-us\\":{\\"name\\":\\"My App\\",\\"resources\\":\\"lang/english\\"},\\"fr-fr\\":{\\"name\\":\\"Mon application\\"}},\\"supports\\":{\\"screenSize\\":{\\"w\\":300,\\"h\\":300}}}"`; exports[`when there is a device entry point present when there are compiled language files sets the i18n[lang].resources key for language files that pass through 1`] = ` Object { diff --git a/src/componentManifest.ts b/src/componentManifest.ts index acad364a..9b1f2bd2 100644 --- a/src/componentManifest.ts +++ b/src/componentManifest.ts @@ -17,32 +17,36 @@ const manifestPath = 'manifest.json'; /** * Descriptor for localized resources. */ -interface Locales { +interface Locale { + /** + * Localized name of the app. + * + * On device, this field is capped at 30 bytes (not including the null + * char). + */ + name?: string; +} + +interface DeviceLocale extends Locale { + /** + * Path to the resources file for the locale, relative to the manifest file. + * + * This file is generated from the corresponding '.po' file using an + * internal, more compact format. On device, this field is capped at + * 256 bytes (not including the null char). + * @example 'l/en-US' + */ + resources?: string; +} + +interface Locales { /** * Lower case locale name. * * On device, this field is capped at 20 bytes (not including the null char). * @example 'en-us' */ - [locale: string]: { - /** - * Localized name of the app. - * - * On device, this field is capped at 30 bytes (not including the null - * char). - */ - name?: string; - - /** - * Path to the resources file for the locale, relative to the manifest file. - * - * This file is generated from the corresponding '.po' file using an - * internal, more compact format. On device, this field is capped at - * 256 bytes (not including the null char). - * @example 'l/en-US' - */ - resources?: string; - }; + [locale: string]: LocaleType; } interface ComponentManifest { @@ -88,6 +92,14 @@ interface ComponentManifest { * On device, this field is capped at 36 bytes (not including the null char). */ uuid: string; + + /** + * List of localized resources. + * + * On device, when this field is read, the value of the `i18n` field is + * capped to 1024 bytes (not including the null char). + */ + i18n: Locales; } interface DeviceManifest extends ComponentManifest { @@ -116,7 +128,7 @@ interface DeviceManifest extends ComponentManifest { * On device, when this field is read, the value of the `i18n` field is * capped to 1024 bytes (not including the null char). */ - i18n: Locales; + i18n: Locales; /** * Path to the app icon file. @@ -185,6 +197,13 @@ function makeCommonManifest({ buildId: string; apiVersion: string; }): ComponentManifest { + // Ensure the default language is the first listed in the manifest + const locales: Locales = projectConfig.i18n; + const { + [projectConfig.defaultLanguage]: defaultLanguage, + ...otherLocales + } = locales; + return { apiVersion, buildId, @@ -192,6 +211,16 @@ function makeCommonManifest({ uuid: projectConfig.appUUID, name: projectConfig.appDisplayName, requestedPermissions: projectConfig.requestedPermissions, + // FW is case sensitive for locales, it insists on everything being lowercase + // Doing this too early means the casing won't match the developers defaultLanguage + // setting, so do it as late as possible + i18n: lodash.mapKeys( + { + [projectConfig.defaultLanguage]: defaultLanguage, + ...otherLocales, + }, + (_, locale) => locale.toLowerCase(), + ), }; } @@ -204,7 +233,7 @@ export function makeDeviceManifest({ buildId: string; targetDevice: string; }) { - const locales: Locales = projectConfig.i18n; + const locales: Locales = projectConfig.i18n; let entryPoint: string | undefined; return new Transform({ @@ -243,12 +272,6 @@ export function makeDeviceManifest({ }, flush(done) { - // Ensure the default language is the first listed in the manifest - const { - [projectConfig.defaultLanguage]: defaultLanguage, - ...otherLocales - } = locales; - if (!entryPoint) { return done( new PluginError( @@ -273,16 +296,6 @@ export function makeDeviceManifest({ apiVersion: deviceApi, }), ...(supports && { supports }), - // FW is case sensitive for locales, it insists on everything being lowercase - // Doing this too early means the casing won't match the developers defaultLanguage - // setting, so do it as late as possible - i18n: lodash.mapKeys( - { - [projectConfig.defaultLanguage]: defaultLanguage, - ...otherLocales, - }, - (_, locale) => locale.toLowerCase(), - ), ...(projectConfig.appType !== AppType.CLOCKFACE && { iconFile: projectConfig.iconFile, wipeColor: projectConfig.wipeColor,