Skip to content

Commit

Permalink
completion
Browse files Browse the repository at this point in the history
  • Loading branch information
ArrayIterator committed Oct 14, 2024
1 parent 0d25473 commit b74a6de
Show file tree
Hide file tree
Showing 13 changed files with 733 additions and 108 deletions.
21 changes: 16 additions & 5 deletions examples/example-en-translation.json → examples/example.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
"flags": ["fuzzy", "c-format"],
"references": ["src/file.js:10"],
"comments": "This is a comment about the translation file.",
"extracted_comments": [
"This is an extracted comment about the translation file."
],
"headers": {
"project-id-version": "My Project 1.0",
"pot-creation-date": "2023-10-01 12:00+0000",
"po-revision-date": "2023-10-01 12:00+0000",
"creation-date": "2023-10-01 12:00+0000",
"revision-date": "2023-10-01 12:00+0000",
"last-translator": "John Doe <[email protected]>",
"language-team": "English <[email protected]>",
"language": "en",
Expand Down Expand Up @@ -39,16 +42,24 @@
"context1": [
{
"msgid": "Hello, world!",
"msgstr": ["Hello, world!"],
"msgid_plural": "Hello, worlds!",
"msgstr": [
"Hello, world!",
"Hello, worlds!"
],
"comments": "This is a comment for the translator as a string.",
"references": ["src/file.js:10"],
"flags": ["fuzzy"]
}
],
"context2withObject": {
"Hello world!": {
"msgid": "Hello, world!",
"msgstr": ["Hello, world!"],
"msgid": "The Cat",
"msgid_plural": "The Cats",
"msgstr": [
"The Cat",
"The Cats"
],
"comments": [
"the key is the msgid",
"the key will ignore or just be as a key reference"
Expand Down
Binary file added examples/example.mo
Binary file not shown.
44 changes: 44 additions & 0 deletions examples/example.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# This is a comment about the translation file.
#, fuzzy, c-format
msgid ""
msgstr ""
"Project-Id-Version: My Project 1.0\n"
"PO-Revision-Date: 2023-10-01 12:00+0000\n"
"Last-Translator: John Doe <[email protected]>\n"
"Language-Team: English <[email protected]>\n"
"Language: en\n"
"Language-Name: English\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. This is a comment for the translator as a string.
msgctxt ""
msgid "as a key reference"
msgstr "as a key reference"

#. This is a comment for the translator as a string.
#: src/file.js:10
#, fuzzy
msgctxt "context1"
msgid "Hello, world!"
msgid_plural "Hello, worlds!"
msgstr[0] "Hello, world!"
msgstr[1] "Hello, worlds!"

#: src/file.js:10
# the key is the msgid
#. the key will ignore or just be as a key reference
#, fuzzy
msgctxt "context2withObject"
msgid "The Cat"
msgid_plural "The Cats"
msgstr[0] "The Cat"
msgstr[1] "The Cats"

#~#: src/file.js:10
#~#, fuzzy
#~ msgctxt "context2withObject"
#~ msgid "Hello, world!"
#~ msgstr "Hello, world!"
35 changes: 0 additions & 35 deletions examples/example.pot

This file was deleted.

90 changes: 90 additions & 0 deletions examples/example.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<translation
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../src/Schema/translation.xsd"
revision="1"
>
<flags>
<item>fuzzy</item>
<item>c-format</item>
</flags>
<references>
<item>src/file.js:10</item>
</references>
<comments>
<item>This is a comment about the translation file.</item>
</comments>
<headers>
<project-id-version>My Project 1.0</project-id-version>
<creation-date>2023-10-01 12:00+0000</creation-date>
<revision-date>2023-10-01 12:00+0000</revision-date>
<last-translator>John Doe &lt;[email protected]&gt;</last-translator>
<language-team>English &lt;[email protected]&gt;</language-team>
<language>en</language>
<mime-version>1.0</mime-version>
<content-type>text/plain; charset=UTF-8</content-type>
<content-transfer-encoding>8bit</content-transfer-encoding>
<plural-forms>nplurals=2; plural=(n != 1);</plural-forms>
</headers>
<translations>
<context name="">
<item>
<comments>
<item>This is a comment for the translator as a string.</item>
</comments>
<disabled/>
<msgid>as a key reference</msgid>
<msgid_plural/>
<msgstr/>
</item>
<item>
<comments/>
<references/>
<flags/>
<msgid/>
<msgid_plural>Hello, worlds!</msgid_plural>
<msgstr>
<item>Hello, world!</item>
<item>Hello, worlds!</item>
</msgstr>
</item>
<item>
<comments>
<item>the key is the msgid</item>
<item>the key will ignore or just be as a key reference</item>
</comments>
<references>
<item>src/file.js:10</item>
</references>
<flags>
<item>fuzzy</item>
</flags>
<msgid>The Cat</msgid>
<msgid_plural>The Cats</msgid_plural>
<msgstr>
<item>The Cat</item>
<item>The Cats</item>
</msgstr>
</item>
<item>
<comments>
<item>this translation is disabled or just as commented translation like po file with: #~ msgid
"Hello, world!"
</item>
</comments>
<references>
<item>src/file.js:10</item>
</references>
<flags>
<item>fuzzy</item>
<item>fuzzy</item>
</flags>
<enable>false</enable>
<msgid>Hello, world!</msgid>
<msgstr>
<item>Hello, world!</item>
</msgstr>
</item>
</context>
</translations>
</translation>
179 changes: 179 additions & 0 deletions src/Gettext/Generator/JsonGenerator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import GettextGeneratorInterface from '../Interfaces/Generator/GettextGeneratorInterface';
import TranslationEntriesInterface from '../../Translations/Interfaces/TranslationEntriesInterface';
import StreamBuffer from '../../Utils/StreamBuffer';
import TranslationEntries from '../../Translations/TranslationEntries';
import InvalidArgumentException from '../../Exceptions/InvalidArgumentException';
import GettextTranslationAttributesInterface from '../Interfaces/Metadata/GettextTranslationAttributesInterface';
import {is_string} from '../../Utils/Helper';
import {
DEFAULT_HEADERS,
HEADER_CONTENT_TYPE_KEY
} from '../Definitions/HeaderDefinitions';
import {
ATTRIBUTE_MESSAGE_ID,
ATTRIBUTE_MESSAGE_ID_PLURAL,
ATTRIBUTE_MESSAGE_STR
} from '../Definitions/AttributeDefinitions';

/**
* The translation generator for JSON files
*/
export default class PoGenerator implements GettextGeneratorInterface {
/**
* Generate the JSON translation file content
* @inheritDoc
* @throws {InvalidArgumentException} if the translations are not an instance of TranslationEntries
*/
public generate(translations: TranslationEntriesInterface): StreamBuffer {
if (!(translations instanceof TranslationEntries)) {
throw new InvalidArgumentException(
`The translations must be an instance of ${TranslationEntries.name}, ${typeof translations} given`
);
}
type TranslationJSON = {
revision: number,
flags?: Array<string>,
references?: Array<[string, Array<number>]>,
comments?: Array<string>,
headers: {[key: string]: string};
translations: {[key: string]: any}
}
let headerLowerCaseKey : {
[key: string]: string
} = {};
for (let key in DEFAULT_HEADERS) {
headerLowerCaseKey[key.toLowerCase()] = key;
}
const json : TranslationJSON = {
revision: translations.getRevision(),
flags: undefined,
references: undefined,
comments: undefined,
headers: headerLowerCaseKey,
translations: {
'': {
'': {
'msgid': '',
'msgstr': ''
}
}
}
} as TranslationJSON;

/**
* Appending the attributes
*/
const append_to_json = (obj: {
[key: string]: any
}, attribute: GettextTranslationAttributesInterface) : void => {
const flags = attribute.getFlags().flags;
if (flags.length > 0) {
obj['flags'] = flags;
} else {
delete obj['flags'];
}
const references = attribute.getReferences();
if (references.length > 0) {
obj['references'] = [];
references.forEach(([file, lines]) => {
if (lines.length === 0) {
obj['references'].push(file);
return;
}
lines.forEach((line) => {
obj['references'].push(`${file}:${line}`);
});
});
} else {
delete obj['references'];
}
const comments = attribute.getComments();
if (comments.length > 0) {
obj['comments'] = comments.length > 0 ? comments : comments.all[0];
if (!is_string(obj['comments'])) {
delete obj['comments'];
}
} else {
delete obj['comments'];
}
const extractedComments = attribute.getExtractedComments();
if (extractedComments.length > 0) {
obj['extracted-comments'] = extractedComments.length > 0 ? extractedComments : extractedComments.all[0];
if (!is_string(obj['extracted-comments'])) {
delete obj['extracted-comments'];
}
} else {
delete obj['extracted-comments'];
}
}
// append json attributes
append_to_json(json, translations.getAttributes());
const headers = translations.getHeaders().clone();
if (!headers.has(HEADER_CONTENT_TYPE_KEY)) {
headers.set(HEADER_CONTENT_TYPE_KEY, DEFAULT_HEADERS[HEADER_CONTENT_TYPE_KEY]);
}
headers.forEach((header, key) => {
switch (key.toLowerCase()) {
case HEADER_CONTENT_TYPE_KEY.toLowerCase():
if (!is_string(header) || header === '') {
header = DEFAULT_HEADERS[HEADER_CONTENT_TYPE_KEY];
}
// get charset
let matchCharset = header.match(/charset=\s*([a-zA-Z0-9-]+)\s*/i);
header = `text/plain; charset=${matchCharset ? matchCharset[1] : 'UTF-8'}`;
break;
case 'pot-creation-date':
key = 'creation-date';
break;
case 'po-revision-date':
key = 'revision-date';
break;
}
// make key lowercase
key = key.toLowerCase();
json.headers[key] = header;
});
// add translations
translations.getEntries().forEach(([_key, entry]) => {
const context = entry.getContext() || '';
const attributes = entry.getAttributes();
const original = entry.getOriginal();
const translation = entry.getTranslation() || '';
const plural = entry.getPlural();
const pluralTranslations = Array.from(entry.getPluralTranslations());
if (!json.translations[context]) {
json.translations[context] = [];
}
let content : {
[key: string]: any
} = {
[ATTRIBUTE_MESSAGE_ID]: original,
};
if (context === '' && original === '') {
// empty translation for the context
content[ATTRIBUTE_MESSAGE_STR] = '';
} else {
if (plural) {
content[ATTRIBUTE_MESSAGE_ID_PLURAL] = plural;
}
if (pluralTranslations.length > 0) {
pluralTranslations.unshift(translation);
content[ATTRIBUTE_MESSAGE_STR] = pluralTranslations;
} else {
content[ATTRIBUTE_MESSAGE_STR] = translation;
}
if (!entry.isEnabled()) {
// disable the translation
content['enable'] = false;
}
}
append_to_json(content, attributes);
if (Array.isArray(content[ATTRIBUTE_MESSAGE_STR])) {
json.translations[context].push(content);
} else {
json.translations[context][original] = content;
}
});
return new StreamBuffer(JSON.stringify(json, null, 4));
}
}
Loading

0 comments on commit b74a6de

Please sign in to comment.