Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions src/__snapshots__/componentManifest.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -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 [],
Expand Down Expand Up @@ -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 [],
Expand All @@ -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 [],
Expand Down Expand Up @@ -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 {
Expand Down
89 changes: 51 additions & 38 deletions src/componentManifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<LocaleType = Locale> {
/**
* 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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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<DeviceLocale>;

/**
* Path to the app icon file.
Expand Down Expand Up @@ -185,13 +197,30 @@ function makeCommonManifest({
buildId: string;
apiVersion: string;
}): ComponentManifest {
// Ensure the default language is the first listed in the manifest
const locales: Locales<DeviceLocale> = projectConfig.i18n;
const {
[projectConfig.defaultLanguage]: defaultLanguage,
...otherLocales
} = locales;

return {
apiVersion,
buildId,
bundleDate: new Date().toISOString(),
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(),
),
};
}

Expand All @@ -204,7 +233,7 @@ export function makeDeviceManifest({
buildId: string;
targetDevice: string;
}) {
const locales: Locales = projectConfig.i18n;
const locales: Locales<DeviceLocale> = projectConfig.i18n;
let entryPoint: string | undefined;

return new Transform({
Expand Down Expand Up @@ -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(
Expand All @@ -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,
Expand Down