Skip to content

Commit

Permalink
Update the i18n automation scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
peterMuriuki committed Dec 5, 2024
1 parent 4b3f2e3 commit b09281d
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 34 deletions.
6 changes: 6 additions & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
# scripts

Home of tiny bespoke and lightweight utility code that automates common code maintenance and shipping tasks.

These include:

1. i18n - cli utility that one can use to manage internationalization tasks on the repository
72 changes: 72 additions & 0 deletions scripts/i18n/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# I!8n Script

Automates i18n tasks across the repository i.e extracting, and updating translation string.

## Features

Read more on how fhir-web structures internationalization in this [guide]()

**Extract Translations**

```shell
# pwd is repo root.
cd scripts

# enable corepack to better manage node js package managers
corepack enable

# install packages
yarn install

# Extract all translatable strings to i18n package, eusm project to both english and french resource files
./i18n/cli.js extract --project eusm -l en,fr
# Extract translatable strings from the fhir-clients package to i18n package > eusm project > fhir-clients namespace> english resource file
./i18n/cli.js extract fhir-clients --project eusm -l en
```

Consider a scenario where you have a view say `fhir-location-management.ListView` that is re-used in more than two places with different semantics. Now how would one support translations if the 2 views should show different set of texts within the same language.

We use the concept of namespaces. Pass a namespace config to the ListView i18n configuration that determines which texts to pick even within the same language. Furthermore we regenerate and store a copy of the translation strings under the new namespace. The end results is 2 namespaces that are usable from the same module but that define different string translations for the same lookup text.

To generate a new namespace for a module

```shell
# Extract translatable strings from the fhir-locations package to i18n package > eusm project> fhir-service-points namespace > english resource file
./i18n/cli.js extract fhir-locations --project eusm -l en --output-namespace fhir-service-points
```

**Download Translations**

Merges previously extracted translations into a single duplicate-free translation file. This file can then be uploaded to translation services like Transifex for translation.

```shell
# pwd is repo root.
cd scripts

# enable corepack to better manage node js package managers
corepack enable

# install packages
yarn install

# Downloads all extracted strings in all the generated english resource files in the eusm project.
./i18n/cli.js download --project eusm -l en
```

**Upload Translations**

Undoes a download operation. Takes a translated resource file, unravels the translations into the individual resource files in the i18n package.

```shell
# pwd is repo root.
cd scripts

# enable corepack to better manage node js package managers
corepack enable

# install packages
yarn install

# Downloads all extracted strings in all the generated english resource files in the eusm project.
./i18n/cli.js upload --project eusm -l en -tfile <file-path-to-resource-file>
```
11 changes: 5 additions & 6 deletions scripts/i18n-cli.js → scripts/i18n/cli.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#!/usr/bin/env node
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import { downloadStrings } from './downloadMerged.js';
import { uploadTranslations } from './uploadMerged.js';
import { runExtractions, supportedProjectCodes, supportedLocaleCodes } from './extract.js';
import { downloadStrings } from './lib/downloadMerged.js';
import { uploadTranslations } from './lib/uploadMerged.js';
import { runExtractions, supportedProjectCodes, supportedLocaleCodes } from './lib/extract.js';

// Define global options and configure commands
yargs(hideBin(process.argv))
Expand Down Expand Up @@ -91,11 +91,10 @@ yargs(hideBin(process.argv))
type: 'string',
demandOption: true,
},
locales: {
locale: {
alias: 'l',
describe: 'Extracted strings will be generated for this locale(s)',
describe: 'Upload strings for this locale',
choices: supportedLocaleCodes,
type: 'array',
default: ['en'],
},
});
Expand Down
File renamed without changes.
File renamed without changes.
35 changes: 35 additions & 0 deletions scripts/i18n/lib/uploadMerged.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import path from 'path';
import fs from 'fs';
import {
ensureFilePath,
getLocaleFilePaths,
getLocaleFolderPaths,
REPO_ROOT_PATH,
} from './utils.js';

function processNamespace(namespace, unifiedJson, locale) {
const baseLocale = 'en';
const enReferenceResourceFile = `${namespace}/${baseLocale}.json`;
const destReferenceResourceFile = `${namespace}/${locale}.json`;
const referenceDict = JSON.parse(fs.readFileSync(enReferenceResourceFile, 'utf-8'));
ensureFilePath(destReferenceResourceFile);
const updatedStringMap = {};
console.log({ referenceDict });
for (const key in referenceDict) {
let updateValue = unifiedJson[key] ?? key;
updatedStringMap[key] = updateValue;
}
fs.writeFileSync(destReferenceResourceFile, JSON.stringify(updatedStringMap, undefined, 2));
}

export async function uploadTranslations(inFile, projectCode = 'core', locale = 'en') {
const unifiedJson = JSON.parse(fs.readFileSync(inFile, 'utf-8'));
const resourceFolders = await getLocaleFolderPaths(projectCode);
for (const namespace of resourceFolders) {
if (!namespace.includes('fhir-client')) {
continue;
}
const qualifiedNamespacePath = path.resolve(REPO_ROOT_PATH, namespace);
processNamespace(qualifiedNamespacePath, unifiedJson, locale);
}
}
14 changes: 14 additions & 0 deletions scripts/utils.js → scripts/i18n/lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,20 @@ export const getLocaleFilePaths = async (projectCode, locale) => {
});
};

/**
* uses glob to get all the generated translation files for each package
* as they reside in the package/i18n package
* @param {string} projectCode informs on the namespace for which the translation files lie.
* @param {string} locale informs which local files to pick under the project code namespace
* @Returns {string[]} - matched paths
*/
export const getLocaleFolderPaths = async (projectCode, locale) => {
const workspacesGlob = `packages/i18n/locales/${projectCode}/*/`;
return promisedGlob(workspacesGlob, { cwd: REPO_ROOT_PATH }).catch(() => {
return [];
});
};

/**
* Ensures the directory for the given file path exists. If not, creates it synchronously.
* @param {string} filePath - The full file path to ensure.
Expand Down
File renamed without changes.
File renamed without changes.
28 changes: 0 additions & 28 deletions scripts/uploadMerged.js

This file was deleted.

0 comments on commit b09281d

Please sign in to comment.