-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
22 changed files
with
1,411 additions
and
223 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
const PO = require('./formats/PO'); | ||
const JSON = require('./formats/JSON'); | ||
const JSON5 = require('./formats/JSON5'); | ||
const CSV = require('./formats/CSV'); | ||
const UnsupportedFormatError = require('./errors/UnsupportedFormatError'); | ||
|
||
const formatHandler = new Map([ | ||
['po', PO], | ||
['json', JSON], | ||
['json5', JSON5], | ||
['csv', CSV], | ||
]); | ||
|
||
class LocaleDirectory { | ||
constructor(directoryPath, defaultFormat) { | ||
this.directoryPath = directoryPath; | ||
} | ||
|
||
buildFilename(locale, format) { | ||
const basename = [locale, format].filter(p => p).join('.'); | ||
|
||
return path.resolve(this.directoryPath, `${basename}`); | ||
} | ||
|
||
writeLocalization(locale, localization, format) { | ||
const filename = this.buildFilename(locale, format); | ||
if (!handler) { | ||
throw new UnsupportedFormatError(format); | ||
} | ||
const handler = formatHandler.get(format); | ||
const data = handler.stringify(localization); | ||
|
||
fs.writeSync(filename, data); | ||
} | ||
|
||
ensureDirectory() { | ||
fs.ensureDirSync(this.templateDirectory); | ||
} | ||
|
||
readLocalization(locale, format) { | ||
const filename = this.buildFilename(locale, format); | ||
const handler = formatHandler.get(format); | ||
if (!handler) { | ||
throw new UnsupportedFormatError(format); | ||
} | ||
const text = String(fs.readSync(filename)); | ||
|
||
return handler.parse(text); | ||
} | ||
|
||
normalizeTo(format) { | ||
formatHandler.entries().forEach(([extension, handler]) => { | ||
if (extension !== format) { | ||
} | ||
}); | ||
} | ||
} | ||
|
||
module.exports = LocaleDirectory; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
class UnsupportedFormatError extends Error { | ||
constructor(format) { | ||
super(`"${format}" is not a supported format`); | ||
} | ||
} | ||
|
||
module.exports = UnsupportedFormatError; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/* | ||
# translator-comments | ||
#. extracted-comments | ||
#: reference… | ||
#, flag… | ||
#| msgid previous-untranslated-string | ||
msgid untranslated-string | ||
msgstr translated-string | ||
*/ | ||
|
||
class CSV { | ||
static parse() { | ||
} | ||
|
||
static stringify() { | ||
} | ||
} | ||
|
||
module.exports = CSV; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/* | ||
# translator-comments | ||
#. extracted-comments | ||
#: reference… | ||
#, flag… | ||
#| msgid previous-untranslated-string | ||
msgid untranslated-string | ||
msgstr translated-string | ||
*/ | ||
|
||
class _JSON { | ||
static parse(text) { | ||
return JSON.parse(text); | ||
} | ||
|
||
static stringify(data) { | ||
return JSON.stringify(data); | ||
} | ||
} | ||
|
||
module.exports = _JSON; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
/* | ||
# translator-comments | ||
#. extracted-comments | ||
#: reference… | ||
#, flag… | ||
#| msgid previous-untranslated-string | ||
msgid untranslated-string | ||
msgstr translated-string | ||
*/ | ||
|
||
const path = require('path'); | ||
const JSON5 = require('json5'); | ||
const jju = require('jju'); | ||
|
||
function isWhitespace(token) { | ||
return token.type === 'whitespace' || token.type === 'newline'; | ||
} | ||
|
||
function removeCommentMarkers(text) { | ||
if (text.startsWith('//')) { | ||
return text.slice(2); | ||
} else if (text.startsWith('/*')) { | ||
return text.slice(2, -2); | ||
} | ||
|
||
return text | ||
} | ||
|
||
function parseComments(text) { | ||
const tokens = jju.tokenize(text).filter((t) => !isWhitespace(t)); | ||
let buffer = []; | ||
const comments = {}; | ||
|
||
tokens.forEach((t) => { | ||
if (t.type === 'comment') { | ||
buffer.push(removeCommentMarkers(t.raw)); | ||
} else if (t.type === 'key') { | ||
if (buffer.length) { | ||
const leaf = t.stack.reduce((node, key) => { | ||
const subNode = node [key] = node[key] || {}; | ||
return subNode; | ||
}, comments); | ||
|
||
leaf[t.value] = buffer; | ||
buffer = []; | ||
} | ||
} else { | ||
buffer = []; | ||
} | ||
}); | ||
|
||
return comments; | ||
} | ||
|
||
/* | ||
# translator-comments | ||
#. extracted-comments | ||
#: reference… | ||
#, flag… | ||
#| msgid previous-untranslated-string | ||
msgid untranslated-string | ||
msgstr translated-string | ||
*/ | ||
|
||
/** | ||
* @private | ||
*/ | ||
function serializeLocalizationWithMetaData(localizationWithMetadata) { | ||
const templateDirectory = path.resolve(this.templateDirectory, '..'); | ||
const translations = Object.values(localizationWithMetadata).map((t) => { | ||
const usages = t.usages.map((u) => { | ||
return `${path.relative(templateDirectory, u.filename)}:${u.lineNumber}`; | ||
}).sort(); | ||
|
||
return Object.assign({}, t, {usages}); | ||
}).sort((a, b) => { | ||
return a.key.localeCompare(b.key) || a.context.localeCompare(b.context); | ||
}); | ||
const indent = ' '; | ||
const lines = ['{']; | ||
let previousKey = translations[0].key; | ||
|
||
/* | ||
* EXAMPLE | ||
* { | ||
* "English": { | ||
* // filename:number | ||
* "default": "French" | ||
* } | ||
* } | ||
* | ||
*/ | ||
return translations.reduce((lines, t, i) => { | ||
const {key, context, data, usages, note} = t; | ||
const newLines = []; | ||
|
||
if (i === 0) { | ||
newLines.push(`${indent}"${key}": {`); | ||
} | ||
|
||
if (previousKey !== key) { | ||
newLines.push(`${indent}},`); | ||
newLines.push(`${indent}"${key}": {`); | ||
} else if (i > 0) { | ||
const length = lines.length; | ||
const last = length - 1; | ||
|
||
lines[last] = lines[last] + ','; | ||
} | ||
|
||
if (note) { | ||
newLines.push(`${indent}${indent}// ${note.toUpperCase()}`); | ||
} | ||
|
||
usages.forEach((u) => { | ||
newLines.push(`${indent}${indent}// ${u}`); | ||
}); | ||
|
||
newLines.push(`${indent}${indent}"${context}": ${JSON.stringify(data)}`); | ||
|
||
previousKey = key; | ||
|
||
return lines.concat(newLines); | ||
}, lines).concat([`${indent}}`, '}']).join('\n'); | ||
} | ||
|
||
|
||
class _JSON5 { | ||
static parse(text) { | ||
const comments = parseComments(text); | ||
console.log(JSON.stringify(comments, null, 4)); | ||
const localizations = JSON5.parse(text); | ||
|
||
Object.entries(localizations).forEach(([key, contexts]) => { | ||
Object.entries(contexts).forEach(([context, value]) => { | ||
if (comments[key] && comments[key][context]) { | ||
comments[key][context].forEach((c) => { | ||
const leaf = localizations[key][context]; | ||
|
||
if (c.startsWith(' ')) { | ||
leaf.notes = leaf.notes || ''; | ||
leaf.notes += c.slice(1); | ||
} else if (c.startsWith('. ')) { | ||
leaf.comments = leaf.comments || ''; | ||
leaf.comments += c.slice(2); | ||
} | ||
}); | ||
} | ||
}); | ||
}); | ||
|
||
return localizations; | ||
} | ||
|
||
static stringify(data) { | ||
return serializeLocalizationWithMetaData.call(this, localization); | ||
} | ||
} | ||
|
||
module.exports = _JSON5; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
const JSON5 = require('./JSON5'); | ||
|
||
describe('formats/JSON5', () => { | ||
it('test', () => { | ||
const tokens = JSON5.parse(`{ | ||
"About": { | ||
// Notes | ||
//, src/Application/index.js:40 | ||
"default": "について", | ||
} | ||
}`); | ||
}); | ||
}); |
Oops, something went wrong.