Initial import from local backup (Documents-Playground/pakerpale)

This commit is contained in:
jeonghwa
2026-07-03 05:27:29 +09:00
commit d918e2eddc
2971 changed files with 264195 additions and 0 deletions

View File

@@ -0,0 +1,267 @@
import path from 'path'
import fs from 'fs-extra'
import extractRelativeTimeMessages from '../source/CLDR/extractRelativeTimeMessages'
import getLocalesListInCLDR from '../source/CLDR/getLocalesList'
// CLDR stubs missing translations with English ones.
// This can be used to find out whether a translation is missing.
const LONG_STYLE_TRANSLATION_STUB = `{
"year": {
"previous": "last year",
"current": "this year",
"next": "next year",
"past": "-{0} y",
"future": "+{0} y"
}`
// Generate plurals first, then run this script.
// Generating plurals creates locale folder structure.
//
// ```
// npm run generate-locale-quantifiers
// npm run generate-locale-messages
// // npm run generate-load-all-locales
// ````
for (const locale of getLocalesListInCLDR())
{
if (
// Different variations of "en" language have `en/short.json` and `en/narrow.json`
// which differ from one another by a simple dot, e.g. `yr.` vs `yr`.
// To reduce the resulting bundle size this dot difference is considered unimportant.
locale.indexOf('en-') === 0 ||
// For "pt" language the relative time messages seem to be different
// from all other "pt-" variations which are identical to "pt-PT".
// Seems like a bug in CLDR.
// To reduce the resulting bundle size "pt" language is discarded
// and "pt-PT" is used instead. All other "pt-" variations
// seems to be identical to "pt-PT" so they're not included.
locale.indexOf('pt-') === 0
) {
// Delete the locale folder.
// (previously created by `npm run generate-locale-quantifiers`).
fs.removeSync(path.join(__dirname, '../locale', locale))
continue
}
// console.log(locale)
// "language" is the top-most parent locale of the `locale`.
const language = locale.split('-')[0]
// For "pt" language the relative time messages seem to be different
// from all other "pt-" variations which are identical to "pt-PT".
// Seems like a bug in CLDR.
// To reduce the resulting bundle size "pt" language is discarded
// and "pt-PT" is used instead. All other "pt-" variations
// seems to be identical to "pt-PT" so they're not included.
const localeInCLDR = locale === 'pt' ? 'pt-PT' : locale
const cldrJsonPath = `cldr-dates-full/main/${localeInCLDR}/dateFields.json`
const localeDirectory = path.join(__dirname, '../locale', locale)
const languageDirectory = path.join(__dirname, '../locale', language)
// If there's no pluralization classifier function
// for this language then don't add it.
const quantifyDirectory = findQuantifyDirectory(locale)
const localeMessages = extractRelativeTimeMessages(require(cldrJsonPath))
// "long" messages are always present.
if (!localeMessages.long) {
throw new Error(`Default (long) locale data is missing for locale "${locale}".`)
}
// If there are no translations for a locale then skip it.
if (JSON.stringify(localeMessages.long, null, '\t').indexOf(LONG_STYLE_TRANSLATION_STUB) === 0) {
// console.log(`No translation for "${locale}". Skipping.`)
fs.removeSync(localeDirectory)
continue
}
// "short" messages are always present.
if (!localeMessages.short) {
throw new Error(`Short locale data is missing for locale "${locale}".`)
}
// "narrow" messages are always present.
if (!localeMessages.narrow) {
throw new Error(`Narrow locale data is missing for locale "${locale}".`)
}
// Drop duplicate quantifier messages.
compactQuantifiersData(localeMessages.long)
compactQuantifiersData(localeMessages.short)
compactQuantifiersData(localeMessages.narrow)
// What are "narrow" and "short" styles and how are they constructed:
// http://cldr.unicode.org/translation/plurals#TOC-Narrow-and-Short-Forms
// Create `index.js` file in the locale directory.
fs.outputFileSync(
path.join(localeDirectory, 'index.js'),
`
module.exports = {
${[
"locale: '" + locale + "'",
"long: require('" + createTimeLabels(locale, 'long', localeMessages) + "')",
"short: require('" + createTimeLabels(locale, 'short', localeMessages) + "')",
"narrow: require('" + createTimeLabels(locale, 'narrow', localeMessages) + "')",
quantifyDirectory && ("quantify: require('" + quantifyDirectory + "/quantify')")
]
.filter(_ => _)
.join(',\n\t')}
}
`.trim()
)
// Remove all locales containing just `index.js`
// which means they're fully inherting from their parent locale.
for (const locale of getLocalesListGenerated()) {
const files = fs.readdirSync(path.join(__dirname, '../locale', locale))
if (files.length === 1 && files[0] === 'index.js') {
fs.removeSync(path.resolve(__dirname, '../locale', locale))
}
}
// Remove strange locales.
fs.removeSync(path.resolve(__dirname, '../locale/en-001'))
fs.removeSync(path.resolve(__dirname, '../locale/en-150'))
fs.removeSync(path.resolve(__dirname, '../locale/en-US-POSIX'))
fs.removeSync(path.resolve(__dirname, '../locale/es-419'))
}
/**
* CLDR data always has relative time messages duplicated
* for all keys if they're the same.
* For example, if relative time messages are the same for
* "one", "many" and "other" they will still be duplicated
* in CLDR data files.
* This function removes such duplication to reduce the
* resulting bundle size.
* Mutates the object passed as the argument directly.
* @param {object} flavor — Relative time messages of a given flavor.
*/
function compactQuantifiersData(flavour) {
for (const unit of Object.keys(flavour)) {
for (const pastOrFuture of Object.keys(flavour[unit])) {
for (const quantifier of Object.keys(flavour[unit][pastOrFuture])) {
// "other" is the one holding the relative time message in case of duplication.
if (quantifier === 'other') {
continue
}
if (flavour[unit][pastOrFuture][quantifier] === flavour[unit][pastOrFuture].other) {
delete flavour[unit][pastOrFuture][quantifier]
}
}
}
}
}
/**
* Returns a list of all supported locales.
* @return {string[]}
*/
function getLocalesListGenerated() {
return fs.readdirSync(path.join(__dirname, '../locale'))
.filter(_ => fs.statSync(path.join(__dirname, '../locale', _)).isDirectory())
}
/**
* Creates a file with the time messages
* of a given style for a given locale.
* @param {string} locale
* @param {string} style
* @param {object} localeMessages — Time messages object containing all styles.
* @return {object} The relative path to the time messages file.
*/
function createTimeLabels(locale, style, localeMessages) {
const content = JSON.stringify(localeMessages[style], null, '\t')
// `sr-Cyrl-BA` -> `sr-Cyrl` -> `sr`.
const parentLocale = findParentLocaleHavingFile(locale, `${style}.json`, {
condition: (file) => fs.readFileSync(file, 'utf-8') === content
})
if (parentLocale) {
return `../${parentLocale}/${style}.json`
}
fs.outputFileSync(path.join(__dirname, '../locale', locale, `${style}.json`), content)
return `./${style}.json`
}
/**
* Returns the relative path to a directory where
* `quantify.js` resides for a given locale.
* For example, there are different locales: "ar" and "ar-AE".
* But their `quantify()` function is identical.
* Therefore, it's only stored inside `ar` folder
* and `getQuantifyDirectory('ar-AE')` is "../ar".
* @param {string} locale
* @return {string} [directory]
*/
function findQuantifyDirectory(locale) {
// Look in parent locales' folders.
// Example: `sr-Cyrl-BA` -> `sr-Cyrl` -> `sr`.
const parentLocale = findParentLocaleHavingFile(locale, 'quantify.js')
if (parentLocale) {
return `../${parentLocale}`
}
// Look in this locale's folder.
if (fs.existsSync(path.join(__dirname, '../locale', locale, 'quantify.js'))) {
return '.'
}
}
/**
* Returns the relative path to a directory where
* a given "flavor" (short, long, narrow) labels file
* resides for a given locale.
* @param {string} locale
* @param {string} flavor
* @return {string} [directory]
*/
function findFlavorDirectory(locale, flavour) {
// Look in parent locales' folders.
// Example: `sr-Cyrl-BA` -> `sr-Cyrl` -> `sr`.
const parentLocale = findParentLocaleHavingFile(locale, `${flavour}.json`, { self: true })
if (parentLocale) {
if (parentLocale === locale) {
return '.'
}
return `../${parentLocale}`
}
}
/**
* Some files are inherited from a parent locale to a child locale.
* For example, there are different locales: "ar" and "ar-AE".
* But their `quantify()` function is identical.
* Therefore, it's only stored inside `ar` folder
* and "ar-AE" locale reuses that file.
* @param {string} locale
* @param {string} fileName
* @param {object} [options]
* @param {boolean} [options.self] — Allow returning same `locale`.
* @param {function} [options.condition] — An extra condition imposed on the absolute file path of the file.
* @return {string} [locale]
*/
function findParentLocaleHavingFile(locale, fileName, options = {}) {
const restParts = locale.split('-')
const parts = []
let inheritFrom
while (restParts.length > 0) {
parts.push(restParts.shift())
const parentLocale = parts.join('-')
if (!options.self && parentLocale === locale) {
continue
}
if (!fs.existsSync(path.join(__dirname, '../locale', parentLocale))) {
continue
}
if (fs.existsSync(path.join(__dirname, '../locale', parentLocale, fileName))) {
if (!options.condition || options.condition(path.join(__dirname, '../locale', parentLocale, fileName))) {
inheritFrom = parentLocale
}
}
}
return inheritFrom
}

View File

@@ -0,0 +1,75 @@
// CLDR data package is periodically being updated.
// `npm install cldr-data@latest --save-dev`
import CLDR from 'cldr-data'
import plurals from 'make-plural'
import MakePlural from 'make-plural/make-plural'
import UglifyJS from 'uglify-js'
import path from 'path'
import fs from 'fs-extra'
import getLocalesListInCLDR from '../source/CLDR/getLocalesList'
const CLDR_LOCALES = getLocalesListInCLDR()
// Generate a pluralization function for each language
for (const locale of Object.keys(plurals)) {
// // Some keys are locales, e.g. "pt-PT".
// // (whatever that means)
// const language = locale.split('-')[0]
// Don't know what the "root" key is for so skip it.
if (locale === 'root') {
continue
}
// If this locale has no relative time labels
// in CLDR data then skip it.
if (CLDR_LOCALES.indexOf(locale) < 0) {
continue
}
// `make-plural` library converts
// CLDR pluralization rules
// into a javascript function.
// https://github.com/eemeli/make-plural.js
const MakePlurals = MakePlural.load(
CLDR('supplemental/plurals'),
// Ordinals aren't needed for relative date/time formatting
// CLDR('supplemental/ordinals')
)
// Pluralization function code
const functionCode = new MakePlurals(locale).toString('classify')
// Minify pluralization function code
let { error, code } = UglifyJS.minify(functionCode)
if (error) {
throw error
}
// Strip function name.
code = code.replace('function classify(', 'function(')
// If quantifier always returns "other"
// it's as if it wasn't specified at all.
if (code === 'function(n){return"other"}') {
continue
}
// Write pluralization function to a file.
fs.outputFileSync(
path.join(__dirname, '../locale', locale, 'quantify.js'),
`module.exports=${code}`
)
}
/**
* Returns a list of all locales supported by CLDR.
* @return {string[]}
*/
function listAllCLDRLocales() {
return fs.readdirSync(path.join(__dirname, '../node_modules/cldr-dates-full/main/'))
.filter(name => fs.statSync(path.join(__dirname, '../node_modules/cldr-dates-full/main', name)).isDirectory())
}