Merge commit '44cd88adc4e2f4028dcc2b08b98368f0dc90cee4' into glitch-soc/merge-upstream

Conflicts:
- `.github/dependabot.yml`:
  Updated upstream, but we've deleted it.
  Keep it deleted.
- `app/javascript/mastodon/locales/index.js`:
  Reworked upstream, but the code was mostly in
  `app/javascript/locales/index.js` in glitch-soc.
  Updated that file accordingly.
- `app/javascript/packs/public.jsx`:
  Not a real conflict, but different imports in
  glitch-soc and upstream.
- `app/views/layouts/application.html.haml`:
  Conflict due to locales loading and theme system
  discrepancies.
  Updated in our own way.
- `app/views/layouts/embedded.html.haml`:
  Conflict due to locales loading and theme system
  discrepancies.
  Updated in our own way.
- `config/webpack/generateLocalePacks.js`:
  Deleted upstream, as upstream now directly loads the
  JSON at runtime.
  Deleted as well, will switch to runtime loading in
  an upcoming commit.
- `config/webpack/shared.js`:
  Not a real conflict, but different imports in
  glitch-soc and upstream.
- `config/webpack/translationRunner.js`:
  Mostly deleted upstream, to be replaced with `formatjs-formatter.js`
  instead.
  Moved the glitch-soc logic there and deleted the file.
This commit is contained in:
Claire
2023-06-10 11:15:05 +02:00
130 changed files with 420 additions and 5081 deletions

View File

@@ -0,0 +1,14 @@
const path = require('path');
const upstreamTranslations = require(path.join(__dirname, "../app/javascript/mastodon/locales/en.json"));
const currentTranslations = require(path.join(__dirname, "../app/javascript/flavours/glitch/locales/en.json"));
exports.format = (msgs) => {
const results = {};
for (const [id, msg] of Object.entries(msgs)) {
if (!upstreamTranslations[id]) {
results[id] = currentTranslations[id] || msg.defaultMessage;
}
}
return results;
};

View File

@@ -1,76 +0,0 @@
// A message from upstream:
// ========================
// To avoid adding a lot of boilerplate, locale packs are
// automatically generated here. These are written into the tmp/
// directory and then used to generate locale_en.js, locale_fr.js, etc.
// Glitch note:
// ============
// This code has been entirely rewritten to support glitch flavours.
// However, the underlying process is exactly the same.
const { existsSync, readdirSync, writeFileSync } = require('fs');
const { join, resolve } = require('path');
const { mkdirp } = require('mkdirp');
const rimraf = require('rimraf');
const { flavours } = require('./configuration');
module.exports = Object.keys(flavours).reduce(function (map, entry) {
const flavour = flavours[entry];
if (!flavour.locales) {
return map;
}
const locales = readdirSync(flavour.locales).filter(filename => {
return /\.json$/.test(filename) &&
!/defaultMessages/.test(filename) &&
!/whitelist/.test(filename);
}).map(filename => filename.replace(/\.json$/, ''));
let inherited_locales_path = null;
if (flavour.inherit_locales && flavours[flavour.inherit_locales]?.locales) {
inherited_locales_path = flavours[flavour.inherit_locales]?.locales;
}
const outPath = resolve('tmp', 'locales', entry);
rimraf.sync(outPath);
mkdirp.sync(outPath);
locales.forEach(function (locale) {
const localePath = join(outPath, `${locale}.js`);
const baseLocale = locale.split('-')[0]; // e.g. 'zh-TW' -> 'zh'
const localeDataPath = [
// first try react-intl
`node_modules/react-intl/locale-data/${baseLocale}.js`,
// then check locales/locale-data
`app/javascript/mastodon/locales/locale-data/${baseLocale}.js`,
// fall back to English (this is what react-intl does anyway)
'node_modules/react-intl/locale-data/en.js',
].filter(
filename => existsSync(filename),
).map(
filename => filename.replace(/(?:node_modules|app\/javascript)\//, ''),
)[0];
const localeContent = `//
// locales/${entry}/${locale}.js
// automatically generated by generateLocalePacks.js
//
${inherited_locales_path ? `import inherited from '../../../${inherited_locales_path}/${locale}.json';` : ''}
import messages from '../../../${flavour.locales}/${locale}.json';
import localeData from '${localeDataPath}';
import { setLocale } from 'locales';
setLocale({
localeData,
${inherited_locales_path ? 'messages: Object.assign({}, inherited, messages)' : 'messages'},
});
`;
writeFileSync(localePath, localeContent, 'utf8');
map[`locales/${entry}/${locale}`] = localePath;
});
return map;
}, {});

View File

@@ -7,7 +7,6 @@ const webpack = require('webpack');
const AssetsManifestPlugin = require('webpack-assets-manifest');
const { env, settings, core, flavours, output } = require('./configuration');
const localePacks = require('./generateLocalePacks');
const rules = require('./rules');
function reducePacks (data, into = {}) {
@@ -49,7 +48,6 @@ function reducePacks (data, into = {}) {
const entries = Object.assign(
{ locales: resolve('app', 'javascript', 'locales') },
localePacks,
reducePacks(core),
Object.values(flavours).reduce((map, data) => reducePacks(data, map), {}),
);

View File

@@ -1,124 +1,3 @@
const fs = require('fs');
const path = require('path');
console.error("The localisation functionality has been refactored, please see the Localisation section in the development documentation (https://docs.joinmastodon.org/dev/code/#localizations)");
// eslint-disable-next-line import/order
const { default: manageTranslations, readMessageFiles } = require('react-intl-translations-manager');
const RFC5646_REGEXP = /^[a-z]{2,3}(?:-(?:x|[A-Za-z]{2,4}))*$/;
const rootDirectory = path.resolve(__dirname, '..', '..');
const externalDefaultMessages = path.resolve(rootDirectory, 'app', 'javascript', 'mastodon', 'locales', 'defaultMessages.json');
const translationsDirectory = path.resolve(rootDirectory, 'app', 'javascript', 'flavours', 'glitch', 'locales');
const messagesDirectory = path.resolve(rootDirectory, 'build', 'messages');
const availableLanguages = fs.readdirSync(translationsDirectory).reduce((languages, filename) => {
const basename = path.basename(filename, '.json');
if (RFC5646_REGEXP.test(basename)) {
languages.push(basename);
}
return languages;
}, []);
const testRFC5646 = language => {
if (!RFC5646_REGEXP.test(language)) {
throw new Error('Not RFC5646 name');
}
};
const testAvailability = language => {
if (!availableLanguages.includes(language)) {
throw new Error('Not an available language');
}
};
const validateLanguages = (languages, validators) => {
const invalidLanguages = languages.reduce((acc, language) => {
try {
validators.forEach(validator => validator(language));
} catch (error) {
acc.push({ language, error });
}
return acc;
}, []);
if (invalidLanguages.length > 0) {
console.error(`
Error: Specified invalid LANGUAGES:
${invalidLanguages.map(({ language, error }) => `* ${language}: ${error.message}`).join('\n')}
Use yarn "manage:translations -- --help" for usage information
`);
process.exit(1);
}
};
const usage = `Usage: yarn manage:translations [OPTIONS] [LANGUAGES]
Manage JavaScript translation files in Mastodon. Generates and update translations in translationsDirectory: ${translationsDirectory}
LANGUAGES
The RFC5646 language tag for the language you want to test or fix. If you want to input multiple languages, separate them with space.
Available languages:
${availableLanguages.join(', ')}
`;
const { argv } = require('yargs')
.usage(usage)
.option('f', {
alias: 'force',
default: false,
describe: 'force using the provided languages. create files if not exists.',
type: 'boolean',
});
// check if message directory exists
if (!fs.existsSync(messagesDirectory)) {
console.error(`
Error: messagesDirectory not exists
(${messagesDirectory})
Try to run "yarn build:development" first`);
process.exit(1);
}
// determine the languages list
const languages = (argv._.length > 0) ? argv._ : availableLanguages;
// validate languages
validateLanguages(languages, [
testRFC5646,
!argv.force && testAvailability,
].filter(Boolean));
// Override `provideExtractedMessages` to ignore translation strings provided upstream already
const provideExtractedMessages = () => {
const extractedMessages = readMessageFiles(messagesDirectory);
const originalExtractedMessages = JSON.parse(fs.readFileSync(externalDefaultMessages, 'utf8'));
const originalKeys = new Set();
originalExtractedMessages.forEach(file => {
file.descriptors.forEach(descriptor => {
originalKeys.add(descriptor.id);
});
});
extractedMessages.forEach(file => {
file.descriptors = file.descriptors.filter((descriptor) => !originalKeys.has(descriptor.id));
});
return extractedMessages.filter((file) => file.descriptors.length > 0);
};
// manage translations
manageTranslations({
messagesDirectory,
translationsDirectory,
detectDuplicateIds: false,
singleMessagesFile: true,
languages,
jsonOptions: {
trailingNewline: true,
},
overrideCoreMethods: {
provideExtractedMessages,
},
});
process.exit(1);