i18n-json-po
Advanced tools
Comparing version 1.0.6 to 1.0.7
129
convert.ts
@@ -1,7 +0,13 @@ | ||
import { I18NEntry, SingleI18NEntry, PluralI18NEntry } from 'i18n-proto'; | ||
import { | ||
I18NEntry, | ||
SingleI18NEntry, | ||
PluralI18NEntry, | ||
TranslationJson, | ||
TranslationMeta | ||
} from 'i18n-proto'; | ||
export type Metadata = { | ||
copyrightSubject: string, | ||
bugsEmail: string, | ||
year: number | ||
export type InitialMeta = { | ||
copyrightSubject?: string, | ||
bugsEmail?: string, | ||
year?: number | ||
}; | ||
@@ -30,7 +36,14 @@ | ||
export function makePoHeader(meta: Metadata, genDate: string): string { | ||
return `# Translations template for PROJECT. | ||
# Copyright (C) ${meta.year} ${meta.copyrightSubject} | ||
export function makePoHeader({ meta, initialMeta, genDate, hasPluralForms }: { | ||
meta?: TranslationMeta, | ||
initialMeta: InitialMeta, | ||
genDate: string, | ||
hasPluralForms: boolean | ||
}): string { | ||
if (!meta) { | ||
// make POT, use initial meta | ||
return `# Translations template for PROJECT. | ||
# Copyright (C) ${initialMeta.year} ${initialMeta.copyrightSubject} | ||
# This file is distributed under the same license as the PROJECT project. | ||
# FIRST AUTHOR <EMAIL@ADDRESS>, ${meta.year}. | ||
# FIRST AUTHOR <EMAIL@ADDRESS>, ${initialMeta.year}. | ||
# | ||
@@ -41,3 +54,3 @@ #, fuzzy | ||
"Project-Id-Version: PROJECT VERSION\\n" | ||
"Report-Msgid-Bugs-To: ${meta.bugsEmail}\\n" | ||
"Report-Msgid-Bugs-To: ${initialMeta.bugsEmail}\\n" | ||
"POT-Creation-Date: ${genDate}\\n" | ||
@@ -53,15 +66,51 @@ "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n" | ||
`; | ||
} else { | ||
// have meta - make po! | ||
let headers = { | ||
projectIdVersion: (v) => `Project-Id-Version: ${v}\n`, | ||
reportMsgidBugsTo: (v) => `Report-Msgid-Bugs-To: ${v}\n`, | ||
potCreationDate: (v) => `POT-Creation-Date: ${v}\n`, | ||
poRevisionDate: (v) => `PO-Revision-Date: ${v}\n`, | ||
lastTranslator: (v) => `Last-Translator: ${v.name} <${v.email}>\n`, | ||
languageTeam: (v) => `Language-Team: ${v}\n`, | ||
mimeVersion: (v) => `MIME-Version: ${v}\n`, | ||
contentType: (v) => `Content-Type: ${v}\n`, | ||
contentTransferEncoding: (v) => `Content-Transfer-Encoding: ${v}\n`, | ||
generatedBy: (v) => `Generated-By: ${v}\n`, | ||
language: (v) => `Language: ${v}\n`, | ||
pluralForms: (v) => `Plural-Forms: ${v}\n`, | ||
}; | ||
let items = [ | ||
'msgid ""', | ||
'msgstr ""', | ||
]; | ||
let pluralFormsHeaderFound = false; | ||
for (let name in meta) { | ||
if (name === 'pluralForms') { | ||
pluralFormsHeaderFound = true; | ||
} | ||
items.push(JSON.stringify(headers[name](meta[name]))); | ||
} | ||
if (hasPluralForms && !pluralFormsHeaderFound) { | ||
throw new Error('Translation has some plural forms, but Plural-Forms header was not found'); | ||
} | ||
return items.join("\n") + "\n\n"; // additional CRLFs to separated header | ||
} | ||
} | ||
export function convert(json: string, meta: Metadata, printOccurences: boolean): string { | ||
const document: I18NEntry[] = JSON.parse(json); | ||
export function convert(json: string, initialMeta: InitialMeta | undefined, printOccurences: boolean): string { | ||
const document: TranslationJson = JSON.parse(json); | ||
let poEntries: PotEntry[] = []; | ||
let hasPluralForms = false; | ||
for (let item of document) { | ||
for (let item of document.items) { | ||
let potEntry = new PotEntry(); | ||
if (item.type === 'single') { | ||
potEntry.parseSingleEntry(item, printOccurences); | ||
potEntry.parseSingleEntry(item, printOccurences, !!document.meta); | ||
} | ||
if (item.type === 'plural') { | ||
potEntry.parsePluralEntry(item, printOccurences); | ||
potEntry.parsePluralEntry(item, printOccurences, !!document.meta); | ||
hasPluralForms = true; | ||
} | ||
@@ -71,5 +120,8 @@ poEntries.push(potEntry); | ||
return makePoHeader(meta, makeDate(new Date())) + poEntries | ||
.map((entry) => entry.asString()) | ||
.join("\n\n"); | ||
return makePoHeader({ | ||
meta: document.meta, | ||
initialMeta, | ||
genDate: makeDate(new Date()), | ||
hasPluralForms | ||
}) + poEntries.map((entry) => entry.asString()).join("\n\n"); | ||
} | ||
@@ -85,6 +137,9 @@ | ||
protected addMsgidPlural = (id: string) => this.items.push('msgid_plural ' + JSON.stringify(id)); | ||
protected addMsgstr = () => this.items.push('msgstr ""'); | ||
protected addMsgstrPlural = (count: number) => { | ||
for (let i = 0; i < count; i++) { | ||
this.items.push('msgstr[' + i + '] ""'); | ||
protected addMsgstr = (translation: string = '') => this.items.push('msgstr ' + JSON.stringify(translation)); | ||
protected addMsgstrPlural = (translations: string[]) => { | ||
if (!translations.length) { // 2 empty translations by default | ||
this.items.push('msgstr[0] ""'); | ||
this.items.push('msgstr[1] ""'); | ||
} else { | ||
translations.forEach((val, index) => this.items.push('msgstr[' + index + '] ' + JSON.stringify(val))); | ||
} | ||
@@ -95,3 +150,7 @@ }; | ||
public parseSingleEntry({ entry, comments, occurences, context, type }: SingleI18NEntry, printOccurences: boolean): PotEntry { | ||
public parseSingleEntry( | ||
{ entry, comments, occurences, context, type, translation }: SingleI18NEntry, | ||
printOccurences: boolean, | ||
includeTranslations: boolean | ||
): PotEntry { | ||
this.items = []; | ||
@@ -110,6 +169,4 @@ if (comments) { | ||
if (type === 'single') { | ||
this.addMsgid(entry); | ||
this.addMsgstr(); | ||
} | ||
this.addMsgid(entry); | ||
this.addMsgstr(includeTranslations ? translation : ''); | ||
@@ -119,3 +176,7 @@ return this; | ||
public parsePluralEntry({ entry, comments, occurences, context, type }: PluralI18NEntry, printOccurences: boolean): PotEntry { | ||
public parsePluralEntry( | ||
{ entry, comments, occurences, context, type, translations }: PluralI18NEntry, | ||
printOccurences: boolean, | ||
includeTranslations: boolean | ||
): PotEntry { | ||
this.items = []; | ||
@@ -134,9 +195,7 @@ if (comments) { | ||
if (type === 'plural') { | ||
this.addMsgid(entry[0]); | ||
// extracted original entries contain only first and | ||
// last plurals forms, which identify the entry | ||
this.addMsgidPlural(entry[1]); | ||
this.addMsgstrPlural(entry.length); | ||
} | ||
this.addMsgid(entry[0]); | ||
// extracted original entries contain only first and | ||
// last plurals forms, which identify the entry | ||
this.addMsgidPlural(entry[1]); | ||
this.addMsgstrPlural(includeTranslations ? translations : []); | ||
@@ -143,0 +202,0 @@ return this; |
@@ -23,23 +23,64 @@ "use strict"; | ||
exports.makeDate = makeDate; | ||
function makePoHeader(meta, genDate) { | ||
return "# Translations template for PROJECT.\n# Copyright (C) " + meta.year + " " + meta.copyrightSubject + "\n# This file is distributed under the same license as the PROJECT project.\n# FIRST AUTHOR <EMAIL@ADDRESS>, " + meta.year + ".\n# \n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PROJECT VERSION\\n\"\n\"Report-Msgid-Bugs-To: " + meta.bugsEmail + "\\n\"\n\"POT-Creation-Date: " + genDate + "\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: i18n-json2po\\n\"\n\n"; | ||
function makePoHeader(_a) { | ||
var meta = _a.meta, initialMeta = _a.initialMeta, genDate = _a.genDate, hasPluralForms = _a.hasPluralForms; | ||
if (!meta) { | ||
// make POT, use initial meta | ||
return "# Translations template for PROJECT.\n# Copyright (C) " + initialMeta.year + " " + initialMeta.copyrightSubject + "\n# This file is distributed under the same license as the PROJECT project.\n# FIRST AUTHOR <EMAIL@ADDRESS>, " + initialMeta.year + ".\n# \n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PROJECT VERSION\\n\"\n\"Report-Msgid-Bugs-To: " + initialMeta.bugsEmail + "\\n\"\n\"POT-Creation-Date: " + genDate + "\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: i18n-json2po\\n\"\n\n"; | ||
} | ||
else { | ||
// have meta - make po! | ||
var headers = { | ||
projectIdVersion: function (v) { return "Project-Id-Version: " + v + "\n"; }, | ||
reportMsgidBugsTo: function (v) { return "Report-Msgid-Bugs-To: " + v + "\n"; }, | ||
potCreationDate: function (v) { return "POT-Creation-Date: " + v + "\n"; }, | ||
poRevisionDate: function (v) { return "PO-Revision-Date: " + v + "\n"; }, | ||
lastTranslator: function (v) { return "Last-Translator: " + v.name + " <" + v.email + ">\n"; }, | ||
languageTeam: function (v) { return "Language-Team: " + v + "\n"; }, | ||
mimeVersion: function (v) { return "MIME-Version: " + v + "\n"; }, | ||
contentType: function (v) { return "Content-Type: " + v + "\n"; }, | ||
contentTransferEncoding: function (v) { return "Content-Transfer-Encoding: " + v + "\n"; }, | ||
generatedBy: function (v) { return "Generated-By: " + v + "\n"; }, | ||
language: function (v) { return "Language: " + v + "\n"; }, | ||
pluralForms: function (v) { return "Plural-Forms: " + v + "\n"; } | ||
}; | ||
var items = [ | ||
'msgid ""', | ||
'msgstr ""', | ||
]; | ||
var pluralFormsHeaderFound = false; | ||
for (var name_1 in meta) { | ||
if (name_1 === 'pluralForms') { | ||
pluralFormsHeaderFound = true; | ||
} | ||
items.push(JSON.stringify(headers[name_1](meta[name_1]))); | ||
} | ||
if (hasPluralForms && !pluralFormsHeaderFound) { | ||
throw new Error('Translation has some plural forms, but Plural-Forms header was not found'); | ||
} | ||
return items.join("\n") + "\n\n"; // additional CRLFs to separated header | ||
} | ||
} | ||
exports.makePoHeader = makePoHeader; | ||
function convert(json, meta, printOccurences) { | ||
function convert(json, initialMeta, printOccurences) { | ||
var document = JSON.parse(json); | ||
var poEntries = []; | ||
for (var _i = 0, document_1 = document; _i < document_1.length; _i++) { | ||
var item = document_1[_i]; | ||
var hasPluralForms = false; | ||
for (var _i = 0, _a = document.items; _i < _a.length; _i++) { | ||
var item = _a[_i]; | ||
var potEntry = new PotEntry(); | ||
if (item.type === 'single') { | ||
potEntry.parseSingleEntry(item, printOccurences); | ||
potEntry.parseSingleEntry(item, printOccurences, !!document.meta); | ||
} | ||
if (item.type === 'plural') { | ||
potEntry.parsePluralEntry(item, printOccurences); | ||
potEntry.parsePluralEntry(item, printOccurences, !!document.meta); | ||
hasPluralForms = true; | ||
} | ||
poEntries.push(potEntry); | ||
} | ||
return makePoHeader(meta, makeDate(new Date())) + poEntries | ||
.map(function (entry) { return entry.asString(); }) | ||
.join("\n\n"); | ||
return makePoHeader({ | ||
meta: document.meta, | ||
initialMeta: initialMeta, | ||
genDate: makeDate(new Date()), | ||
hasPluralForms: hasPluralForms | ||
}) + poEntries.map(function (entry) { return entry.asString(); }).join("\n\n"); | ||
} | ||
@@ -55,12 +96,19 @@ exports.convert = convert; | ||
this.addMsgidPlural = function (id) { return _this.items.push('msgid_plural ' + JSON.stringify(id)); }; | ||
this.addMsgstr = function () { return _this.items.push('msgstr ""'); }; | ||
this.addMsgstrPlural = function (count) { | ||
for (var i = 0; i < count; i++) { | ||
_this.items.push('msgstr[' + i + '] ""'); | ||
this.addMsgstr = function (translation) { | ||
if (translation === void 0) { translation = ''; } | ||
return _this.items.push('msgstr ' + JSON.stringify(translation)); | ||
}; | ||
this.addMsgstrPlural = function (translations) { | ||
if (!translations.length) { | ||
_this.items.push('msgstr[0] ""'); | ||
_this.items.push('msgstr[1] ""'); | ||
} | ||
else { | ||
translations.forEach(function (val, index) { return _this.items.push('msgstr[' + index + '] ' + JSON.stringify(val)); }); | ||
} | ||
}; | ||
this.asString = function () { return _this.items.join("\n"); }; | ||
} | ||
PotEntry.prototype.parseSingleEntry = function (_a, printOccurences) { | ||
var entry = _a.entry, comments = _a.comments, occurences = _a.occurences, context = _a.context, type = _a.type; | ||
PotEntry.prototype.parseSingleEntry = function (_a, printOccurences, includeTranslations) { | ||
var entry = _a.entry, comments = _a.comments, occurences = _a.occurences, context = _a.context, type = _a.type, translation = _a.translation; | ||
this.items = []; | ||
@@ -76,10 +124,8 @@ if (comments) { | ||
} | ||
if (type === 'single') { | ||
this.addMsgid(entry); | ||
this.addMsgstr(); | ||
} | ||
this.addMsgid(entry); | ||
this.addMsgstr(includeTranslations ? translation : ''); | ||
return this; | ||
}; | ||
PotEntry.prototype.parsePluralEntry = function (_a, printOccurences) { | ||
var entry = _a.entry, comments = _a.comments, occurences = _a.occurences, context = _a.context, type = _a.type; | ||
PotEntry.prototype.parsePluralEntry = function (_a, printOccurences, includeTranslations) { | ||
var entry = _a.entry, comments = _a.comments, occurences = _a.occurences, context = _a.context, type = _a.type, translations = _a.translations; | ||
this.items = []; | ||
@@ -95,9 +141,7 @@ if (comments) { | ||
} | ||
if (type === 'plural') { | ||
this.addMsgid(entry[0]); | ||
// extracted original entries contain only first and | ||
// last plurals forms, which identify the entry | ||
this.addMsgidPlural(entry[1]); | ||
this.addMsgstrPlural(entry.length); | ||
} | ||
this.addMsgid(entry[0]); | ||
// extracted original entries contain only first and | ||
// last plurals forms, which identify the entry | ||
this.addMsgidPlural(entry[1]); | ||
this.addMsgstrPlural(includeTranslations ? translations : []); | ||
return this; | ||
@@ -104,0 +148,0 @@ }; |
import * as cli from 'cli'; | ||
import { readFile, writeFile } from 'fs'; | ||
import { convert } from './convert'; | ||
import { convert, InitialMeta } from './convert'; | ||
@@ -37,3 +37,3 @@ const options = cli.parse({ | ||
const meta = { | ||
const meta: InitialMeta = { | ||
copyrightSubject: options.copyrightSubject, | ||
@@ -40,0 +40,0 @@ bugsEmail: options.bugsEmail, |
{ | ||
"name": "i18n-json-po", | ||
"version": "1.0.6", | ||
"version": "1.0.7", | ||
"description": "i18n .json to .pot file converter", | ||
@@ -28,3 +28,3 @@ "main": "dist/index.js", | ||
"eslint": "3.13.1", | ||
"i18n-proto": "1.0.4", | ||
"i18n-proto": "1.0.5", | ||
"karma": "1.7.0", | ||
@@ -31,0 +31,0 @@ "karma-browserify": "^5.1.1", |
@@ -21,3 +21,3 @@ # i18n-json-po | ||
to stdin. | ||
-o / --output FILE Define output POT file name. If a file | ||
-o / --output FILE Define output PO[T] file name. If a file | ||
already exists, it's contents will be | ||
@@ -32,3 +32,3 @@ overwritten. Defaults to stdout. | ||
``` | ||
Be default jsonpo accepts input JSON file from stdin, so it's possible to combine it with [i18n-stex](https://github.com/2gis/stex) nicely: | ||
By default `jsonpo` accepts input JSON file from stdin, so it's possible to combine it with [i18n-stex](https://github.com/2gis/stex) nicely: | ||
``` | ||
@@ -39,2 +39,6 @@ $ stex -s 'src/**/*.ts' | jsonpo -p > strings.pot | ||
### PO and POT | ||
By default, if optional `meta` field is not present in input file, `jsonpo` creates POT (template) file **without any translations**. If you need to add translations into file, you MUST pass `meta` field according to its format. This will result in fully translated PO file. Note that if your translations include plural forms, you MUST provide `pluralForms` member in `meta` field: this field should contain formula describing how to choose proper plural form. See `Plural-Forms` header in gettext's PO file description. | ||
## API usage | ||
@@ -41,0 +45,0 @@ |
import * as assert from 'assert'; | ||
import { PluralI18NEntry, SingleI18NEntry } from 'i18n-proto'; | ||
import { Metadata, PotEntry, makeDate, getTzOffset, makePoHeader } from '../convert'; | ||
import { PluralI18NEntry, SingleI18NEntry, TranslationMeta } from 'i18n-proto'; | ||
import { InitialMeta, PotEntry, makeDate, getTzOffset, makePoHeader } from '../convert'; | ||
const xor = require('array-xor'); | ||
@@ -16,3 +16,3 @@ | ||
it('Makes valid POT header', () => { | ||
let m: Metadata = { | ||
let m: InitialMeta = { | ||
copyrightSubject: 'cool team', | ||
@@ -44,3 +44,7 @@ bugsEmail: 'bugs@team.com', | ||
xor( | ||
makePoHeader(m, 'SOMEDATE').split("\n"), | ||
makePoHeader({ | ||
initialMeta: m, | ||
genDate: 'SOMEDATE', | ||
hasPluralForms: false | ||
}).split("\n"), | ||
expected.split("\n") | ||
@@ -52,2 +56,76 @@ ), | ||
it('Makes valid PO header from existing meta', () => { | ||
let input: TranslationMeta = { | ||
projectIdVersion: '2gis-online', | ||
reportMsgidBugsTo: 'online4@2gis.ru', | ||
potCreationDate: '2017-07-14 11:29+0700', | ||
poRevisionDate: '2017-06-30 15:30+0700', | ||
lastTranslator: { | ||
name: '2GIS', | ||
email: 'crowdin@2gis.ru' | ||
}, | ||
language: 'cs_CZ', | ||
languageTeam: 'Czech', | ||
pluralForms: 'nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2', | ||
mimeVersion: '1.0', | ||
contentType: 'text/plain; charset=utf-8', | ||
contentTransferEncoding: '8bit', | ||
generatedBy: 'Babel 2.1.1' | ||
}; | ||
let expected = `msgid "" | ||
msgstr "" | ||
"Project-Id-Version: 2gis-online\\n" | ||
"Report-Msgid-Bugs-To: online4@2gis.ru\\n" | ||
"POT-Creation-Date: 2017-07-14 11:29+0700\\n" | ||
"PO-Revision-Date: 2017-06-30 15:30+0700\\n" | ||
"Last-Translator: 2GIS <crowdin@2gis.ru>\\n" | ||
"Language: cs_CZ\\n" | ||
"Language-Team: Czech\\n" | ||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2\\n" | ||
"MIME-Version: 1.0\\n" | ||
"Content-Type: text/plain; charset=utf-8\\n" | ||
"Content-Transfer-Encoding: 8bit\\n" | ||
"Generated-By: Babel 2.1.1\\n" | ||
`; | ||
assert.deepEqual(xor( | ||
makePoHeader({ meta: input, initialMeta: {}, genDate: 'SOMEDATE', hasPluralForms: true }).split("\n"), | ||
expected.split("\n") | ||
), []); | ||
}); | ||
it('Properly handles absence of Plural-Forms header', () => { | ||
let input = { | ||
projectIdVersion: '2gis-online', | ||
reportMsgidBugsTo: 'online4@2gis.ru', | ||
potCreationDate: '2017-07-14 11:29+0700', | ||
poRevisionDate: '2017-06-30 15:30+0700', | ||
lastTranslator: { | ||
name: '2GIS', | ||
email: 'crowdin@2gis.ru' | ||
}, | ||
language: 'cs_CZ', | ||
languageTeam: 'Czech', | ||
mimeVersion: '1.0', | ||
contentType: 'text/plain; charset=utf-8', | ||
contentTransferEncoding: '8bit', | ||
generatedBy: 'Babel 2.1.1' | ||
} as TranslationMeta; // Explicit casting to emulate bad JSON | ||
let catched = []; | ||
try { | ||
makePoHeader({ meta: input, initialMeta: {}, genDate: 'SOMEDATE', hasPluralForms: true }) | ||
} catch (e) { | ||
catched.push(e); | ||
} | ||
assert.equal(catched.length, 1); | ||
assert.equal(catched[0].message, 'Translation has some plural forms, but Plural-Forms header was not found'); | ||
// Should not throw exceptions without hasPluralForms | ||
assert.notEqual(makePoHeader({ meta: input, initialMeta: {}, genDate: 'SOMEDATE', hasPluralForms: false }), undefined); | ||
}); | ||
it('Parses single i18n entry', () => { | ||
@@ -78,3 +156,3 @@ let entry = new PotEntry(); | ||
let xor1 = xor( | ||
entry.parseSingleEntry(i18nEntry, true).asString().split("\n"), | ||
entry.parseSingleEntry(i18nEntry, true, true).asString().split("\n"), | ||
expected.split("\n") | ||
@@ -85,3 +163,3 @@ ); | ||
let xor2 = xor( | ||
entry.parseSingleEntry(i18nEntry, false).asString().split("\n"), | ||
entry.parseSingleEntry(i18nEntry, false, true).asString().split("\n"), | ||
expectedWithoutOccurences.split("\n") | ||
@@ -122,3 +200,3 @@ ); | ||
let xor1 = xor( | ||
entry.parsePluralEntry(i18nEntry, true).asString().split("\n"), | ||
entry.parsePluralEntry(i18nEntry, true, true).asString().split("\n"), | ||
expected.split("\n") | ||
@@ -129,3 +207,3 @@ ); | ||
let xor2 = xor( | ||
entry.parsePluralEntry(i18nEntry, false).asString().split("\n"), | ||
entry.parsePluralEntry(i18nEntry, false, true).asString().split("\n"), | ||
expectedWithoutOccurences.split("\n") | ||
@@ -132,0 +210,0 @@ ); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
171727
847
58