Browse Source

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
Koala Yeung 7 years ago
parent
commit
cf0b753209

+ 5 - 0
.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
+

+ 5 - 6
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": "לא ניתן לנגן וידאו"
-}
+}

+ 4 - 5
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",
-};
+  "video_player.video_error": "Nie można odtworzyć pliku wideo"
+}

+ 2 - 0
app/javascript/mastodon/locales/whitelist_he.json

@@ -0,0 +1,2 @@
+[
+]

+ 2 - 0
app/javascript/mastodon/locales/whitelist_pl.json

@@ -0,0 +1,2 @@
+[
+]

+ 2 - 2
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'

+ 78 - 28
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,
+});

+ 3 - 0
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"