From cf0b7532097e7a59d59ea71a89ba39f8a4ab62ad Mon Sep 17 00:00:00 2001 From: Koala Yeung Date: Sat, 6 May 2017 10:05:38 +0800 Subject: [PATCH] Streamline javascript translation by improving translationRunner (#2808) * package.json: Add "build:*" targets * Improve react-intl-translations-manager workflow. * Added "build:production" to build production bundle. * Added "build:development" to build development bundle. * Fix json translation files * Run `yarn manage:translations` to fix translation files. * Fix `pl.json` for syntax error. * translationRunner: auto detect existing languages * Auto detect existing rfc5646 language tag in *.json filenames in `app/javascript/mastodon/locale` folder. No need to manually define every new language in the languages array here. * translationRunner: add more functionality * Allow script user to specify language code to check. * Added available language check. * Added --force flag to force creation of unexists language. * Added --help flag and help messages. * gitignore: ignore npm-debug.log * Fix webpack error if NODE_ENV is not defined Default to use 'development' in config/webpack/configuration.js --- .gitignore | 5 + app/javascript/mastodon/locales/he.json | 11 +- app/javascript/mastodon/locales/pl.json | 9 +- .../mastodon/locales/whitelist_he.json | 2 + .../mastodon/locales/whitelist_pl.json | 2 + config/webpack/configuration.js | 4 +- config/webpack/translationRunner.js | 106 +++++++++++++----- package.json | 3 + 8 files changed, 101 insertions(+), 41 deletions(-) create mode 100644 app/javascript/mastodon/locales/whitelist_he.json create mode 100644 app/javascript/mastodon/locales/whitelist_pl.json diff --git a/.gitignore b/.gitignore index 80df10959..4ac4c56f4 100644 --- a/.gitignore +++ b/.gitignore @@ -46,5 +46,10 @@ redis /public/packs /node_modules + +# Ignore npm debug log +npm-debug.log + # Ignore Docker option files docker-compose.override.yml + diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index f8945dc1c..82f4d323d 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -4,8 +4,8 @@ "account.edit_profile": "עריכת פרופיל", "account.follow": "מעקב", "account.followers": "עוקבים", - "account.follows_you": "במעקב אחריך", "account.follows": "נעקבים", + "account.follows_you": "במעקב אחריך", "account.mention": "אזכור של @{name}", "account.mute": "להשתיק את @{name}", "account.posts": "הודעות", @@ -53,8 +53,9 @@ "emoji_button.travel": "טיולים ואתרים", "empty_column.community": "טור הסביבה ריק. יש לפרסם משהו כדי שדברים יתרחילו להתגלגל!", "empty_column.hashtag": "אין כלום בהאשתג הזה עדיין.", - "empty_column.home.public_timeline": "בפרהסיה", "empty_column.home": "אף אחד לא במעקב עדיין. אפשר לבקר ב{public} או להשתמש בחיפוש כדי להתחיל ולהכיר חצוצרנים אחרים.", + "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", + "empty_column.home.public_timeline": "בפרהסיה", "empty_column.notifications": "אין התראות עדיין. יאללה, הגיע הזמן להתחיל להתערבב!", "empty_column.public": "אין פה כלום! כדי למלא את הטור הזה אפשר לכתוב משהו, או להתחיל לעקוב אחרי אנשים מקהילות אחרות.", "follow_request.authorize": "קבלה", @@ -84,7 +85,6 @@ "navigation_bar.public_timeline": "בפרהסיה", "notification.favourite": "חצרוצך חובב על ידי {name}", "notification.follow": "{name} במעקב אחרייך", - "notification.mention": "אוזכרת ע\"י {name}", "notification.reblog": "חצרוצך הודהד על ידי {name}", "notifications.clear": "הסרת התראות", "notifications.clear_confirmation": "להסיר את כל ההתראות? בטוח?", @@ -131,7 +131,6 @@ "report.submit": "שליחה", "report.target": "דיווח", "search.placeholder": "חיפוש", - "search.status_by": "הודעה מאת {name}", "search_results.total": "{count, number} {count, plural, one {תוצאה} other {תוצאות}}", "status.cannot_reblog": "לא ניתן להדהד הודעה זו", "status.delete": "מחיקה", @@ -145,8 +144,8 @@ "status.reply": "תגובה", "status.replyAll": "תגובה לכולם", "status.report": "דיווח על @{name}", - "status.sensitive_warning": "תוכן רגיש", "status.sensitive_toggle": "לחצו כדי לראות", + "status.sensitive_warning": "תוכן רגיש", "status.show_less": "הראה פחות", "status.show_more": "הראה יותר", "tabs_bar.compose": "חיבור", @@ -162,4 +161,4 @@ "video_player.toggle_sound": "הפעלת\\ביטול שמע", "video_player.toggle_visible": "הפעלת\\ביטול תצוגה", "video_player.video_error": "לא ניתן לנגן וידאו" -} +} \ No newline at end of file diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index 525a35510..1d0bc1ac0 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -53,8 +53,9 @@ "emoji_button.travel": "Podróże i miejsca", "empty_column.community": "Lokalna oś czasu jest pusta. Napisz coś publicznie, aby odbić piłeczkę!", "empty_column.hashtag": "Nie ma postów oznaczonych tym hashtagiem. Możesz napisać pierwszy!", - "empty_column.home.public_timeline": "publiczna oś czasu", "empty_column.home": "Nie obserwujesz nikogo. Odwiedź publiczną oś czasu lub użyj wyszukiwarki, aby znaleźć ciekawych ludzi.", + "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", + "empty_column.home.public_timeline": "publiczna oś czasu", "empty_column.notifications": "Nie masz żadnych powiadomień. Rozpocznij interakcje z innymi użytkownikami.", "empty_column.public": "Tu nic nie ma! Napisz coś publicznie, lub dodaj ludzi z innych instancji, aby to wyświetlić.", "follow_request.authorize": "Autoryzuj", @@ -84,7 +85,6 @@ "navigation_bar.public_timeline": "Oś czasu federacji", "notification.favourite": "{name} dodał twój status do ulubionych", "notification.follow": "{name} zaczął cię obserwować", - "notification.mention": "{name} wspomniał o tobie", "notification.reblog": "{name} podbił twój status", "notifications.clear": "Wyczyść powiadomienia", "notifications.clear_confirmation": "Czy na pewno chcesz bezpowrotnie usunąć wszystkie powiadomienia?", @@ -131,7 +131,6 @@ "report.submit": "Wyślij", "report.target": "Zgłaszanie", "search.placeholder": "Szukaj", - "search.status_by": "Status od {name}", "search_results.total": "{count, number} {count, plural, one {wynik} more {wyniki}}", "status.cannot_reblog": "Ten post nie może zostać podbity", "status.delete": "Usuń", @@ -161,5 +160,5 @@ "video_player.expand": "Przełącz wideo", "video_player.toggle_sound": "Przełącz dźwięk", "video_player.toggle_visible": "Przełącz widoczność", - "video_player.video_error": "Nie można odtworzyć pliku wideo", -}; \ No newline at end of file + "video_player.video_error": "Nie można odtworzyć pliku wideo" +} \ No newline at end of file diff --git a/app/javascript/mastodon/locales/whitelist_he.json b/app/javascript/mastodon/locales/whitelist_he.json new file mode 100644 index 000000000..32960f8ce --- /dev/null +++ b/app/javascript/mastodon/locales/whitelist_he.json @@ -0,0 +1,2 @@ +[ +] \ No newline at end of file diff --git a/app/javascript/mastodon/locales/whitelist_pl.json b/app/javascript/mastodon/locales/whitelist_pl.json new file mode 100644 index 000000000..32960f8ce --- /dev/null +++ b/app/javascript/mastodon/locales/whitelist_pl.json @@ -0,0 +1,2 @@ +[ +] \ No newline at end of file diff --git a/config/webpack/configuration.js b/config/webpack/configuration.js index 61c5b821f..e2f8d2d8b 100644 --- a/config/webpack/configuration.js +++ b/config/webpack/configuration.js @@ -7,8 +7,8 @@ const { readFileSync } = require('fs') const configPath = resolve('config', 'webpack') const loadersDir = join(__dirname, 'loaders') -const paths = safeLoad(readFileSync(join(configPath, 'paths.yml'), 'utf8'))[env.NODE_ENV] -const devServer = safeLoad(readFileSync(join(configPath, 'development.server.yml'), 'utf8'))[env.NODE_ENV] +const paths = safeLoad(readFileSync(join(configPath, 'paths.yml'), 'utf8'))[env.NODE_ENV || 'development'] +const devServer = safeLoad(readFileSync(join(configPath, 'development.server.yml'), 'utf8'))[env.NODE_ENV || 'development'] // Compute public path based on environment and CDN_HOST in production const ifHasCDN = env.CDN_HOST !== undefined && env.NODE_ENV === 'production' diff --git a/config/webpack/translationRunner.js b/config/webpack/translationRunner.js index c636170b9..937c2edd0 100644 --- a/config/webpack/translationRunner.js +++ b/config/webpack/translationRunner.js @@ -1,34 +1,84 @@ +/*eslint no-console: "off"*/ const manageTranslations = require('react-intl-translations-manager').default; +const argv = require('minimist')(process.argv.slice(2)); +const fs = require('fs'); + +const translationsDirectory = 'app/javascript/mastodon/locales'; +const localeFn = /^([a-z]{2,3}(|\-[A-Z]+))\.json$/; +const reRFC5646 = /^[a-z]{2,3}(|\-[A-Z]+)$/; +const availableLanguages = fs.readdirSync(`${process.cwd()}/${translationsDirectory}`).reduce((acc, fn) => { + if (fn.match(localeFn)) { + acc.push(fn.replace(localeFn, '$1')); + } + return acc; +}, []); + +// print help message +if (argv.help !== undefined) { + console.log( +`Usage: yarn manage:translations -- [OPTIONS] [LANGUAGES] + +Manage javascript translation files in mastodon. Generates and update +translations in translationsDirectory: ${translationsDirectory} + +OPTIONS + --help show this message + --force force using the provided languages. create files if not exists. + default: false + +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} +`); + process.exit(0); +} + +// determine the languages list +const languages = (argv._.length === 0) ? availableLanguages : argv._; + +// check if the languages provided are RFC5626 compliant +(function() { + let invalidLanguages = languages.reduce((acc, language) => { + if (!language.match(reRFC5646)) { + acc.push(language); + } + return acc; + }, []); + if (invalidLanguages.length > 0) { + console.log(`Error:`); + for (let language of invalidLanguages) { + console.error(`* Not RFC5626 name: ${language}`); + } + console.log(`\nUse yarn "manage:translations -- --help" for usage information\n`); + process.exit(1); + } +})(); + +// make sure the language exists. Unless force to create locale file. +if (argv.force !== true) { + let invalidLanguages = languages.reduce((acc, language) => { + if (availableLanguages.indexOf(language) < 0) { + acc.push(language); + } + return acc; + }, []); + if (invalidLanguages.length > 0) { + console.log(`Error:`); + for (let language of invalidLanguages) { + console.error(`* Language not available: ${language}`); + } + console.log(`\nIf you want to force creating the language(s) above, please add the --force option.\n`); + process.exit(1); + } +} manageTranslations({ messagesDirectory: 'build/messages', - translationsDirectory: 'app/javascript/mastodon/locales/', + translationsDirectory, detectDuplicateIds: false, singleMessagesFile: true, - languages: [ - 'ar', - 'en', - 'de', - 'es', - 'fa', - 'hr', - 'hu', - 'io', - 'it', - 'fr', - 'nl', - 'no', - 'oc', - 'pt', - 'pt-BR', - 'uk', - 'fi', - 'eo', - 'ru', - 'ja', - 'zh-HK', - 'zh-CN', - 'bg', - 'id', - ], -}) + languages, +}); diff --git a/package.json b/package.json index efe497138..2475918b1 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,8 @@ "license": "AGPL-3.0", "scripts": { "postversion": "git push --tags", + "build:development": "NODE_ENV=development yarn webpack -- --config config/webpack/development.js", + "build:production": "NODE_ENV=production yarn webpack -- --config config/webpack/production.js", "manage:translations": "node ./config/webpack/translationRunner.js", "start": "babel-node ./streaming/index.js --presets es2015,stage-2", "storybook": "start-storybook -p 9001 -c storybook", @@ -113,6 +115,7 @@ "eslint-plugin-jsx-a11y": "^4.0.0", "eslint-plugin-react": "^6.10.3", "jsdom": "^9.11.0", + "minimist": "^1.2.0", "mocha": "^3.2.0", "react-intl-translations-manager": "^5.0.0", "webpack-dev-server": "^2.4.5"