From df86bf20e37a8366d9effaf52a7150b6f3ab350a Mon Sep 17 00:00:00 2001 From: Kerrick Long Date: Sun, 17 Jul 2011 22:29:26 -0500 Subject: [PATCH] Internationalization! --- _locales/en_US/messages.json | 392 +++++++++++++++++++++++++++++++++++ js/common.js | 106 +++++----- manifest.json | 3 +- 3 files changed, 452 insertions(+), 49 deletions(-) create mode 100644 _locales/en_US/messages.json diff --git a/_locales/en_US/messages.json b/_locales/en_US/messages.json new file mode 100644 index 0000000..36887aa --- /dev/null +++ b/_locales/en_US/messages.json @@ -0,0 +1,392 @@ +{ + "just_now": { + "message": "just now", + "description": "Describe that something just happened." + + }, + "a_minute_ago": { + "message": "a minute ago", + "description": "Describe that something happened a minute ago." + + }, + "a_minute_from_now": { + "message": "a minute from now", + "decription": "Describe that something will happen in a minute." + }, + "minutes_ago": { + "message": "$NUM$ minutes ago", + "placeholders": { + "NUM": { + "content": "$1", + "example" : "4" + } + } + }, + "minutes_from_now": { + "message": "$NUM$ minutes from now", + "placeholders": { + "NUM": { + "content": "$1", + "example" : "4" + } + } + }, + "an_hour_ago": { + "message": "an hour ago", + "description": "Describe that something happened an hour ago." + }, + "an_hour_from_now": { + "message": "an hour from now", + "description": "Describe that will happen in an hour." + }, + "hours_ago": { + "message": "$NUM$ hours ago", + "placeholders": { + "NUM": { + "content": "$1", + "example" : "4" + } + } + }, + "hours_from_now": { + "message": "$NUM$ hours from now", + "placeholders": { + "NUM": { + "content": "$1", + "example" : "4" + } + } + }, + "yesterday": { + "message": "yesterday", + "description": "The day before today." + }, + "tomorrow": { + "message": "tomorrow", + "description": "The day after today." + }, + "days_ago": { + "message": "$NUM$ days ago", + "placeholders": { + "NUM": { + "content": "$1", + "example" : "4" + } + } + }, + "days_from_now": { + "message": "$NUM$ days from now", + "placeholders": { + "NUM": { + "content": "$1", + "example" : "4" + } + } + }, + "last_week": { + "message": "last week", + "description": "The week before this one." + }, + "next_week": { + "message": "next week", + "description": "The week after this one." + }, + "weeks_ago": { + "message": "$NUM$ weeks ago", + "placeholders": { + "NUM": { + "content": "$1", + "example" : "4" + } + } + }, + "weeks_from_now": { + "message": "$NUM$ weeks from now", + "placeholders": { + "NUM": { + "content": "$1", + "example" : "4" + } + } + }, + "last_month": { + "message": "last month", + "description": "The month before this one." + }, + "next_month": { + "message": "next month", + "description": "The month after this one." + }, + "months_ago": { + "message": "$NUM$ months ago", + "placeholders": { + "NUM": { + "content": "$1", + "example" : "4" + } + } + }, + "months_from_now": { + "message": "$NUM$ months from now", + "placeholders": { + "NUM": { + "content": "$1", + "example" : "4" + } + } + }, + "last_year": { + "message": "last year", + "description": "The year before this one." + }, + "next_year": { + "message": "next year", + "description": "The year after this one." + }, + "years_ago": { + "message": "$NUM$ years ago", + "placeholders": { + "NUM": { + "content": "$1", + "example" : "4" + } + } + }, + "years_from_now": { + "message": "$NUM$ years from now", + "placeholders": { + "NUM": { + "content": "$1", + "example" : "4" + } + } + }, + "last_century": { + "message": "last century", + "description": "The century before this one." + }, + "next_century": { + "message": "next century", + "description": "The century after this one." + }, + "centuries_ago": { + "message": "$NUM$ centuries ago", + "placeholders": { + "NUM": { + "content": "$1", + "example" : "4" + } + } + }, + "centuries_from_now": { + "message": "$NUM$ centuries from now", + "placeholders": { + "NUM": { + "content": "$1", + "example" : "4" + } + } + }, + "not_activated": { + "message": "$APPNAME$ is not activated for this page. Click to activate.", + "placeholders": { + "APPNAME": { + "content": "Mostly Harmless" + } + } + }, + "loading": { + "message": "Loading data..." + }, + "viewing_comments": { + "message": "You are currently viewing the comments for this page." + }, + "submit_page": { + "message": "Submit this page to $REDDIT$.", + "placeholders": { + "REDDIT": { + "content": "reddit" + } + } + }, + "submitted_num_times": { + "message": "This page has been submitted $NUM$ times.", + "placeholders": { + "NUM": { + "content": "$1", + "example": "4" + } + } + }, + "login": { + "message": "You have to be logged in to do that. $BEGIN_LINK$Click to open the login page.$END_LINK$", + "placeholders": { + "BEGIN_LINK": { + "content": "" + }, + "END_LINK": { + "content": "" + } + } + }, + "api_error": { + "message": "There was an API error. HTTP Status: $STATUS$. Click to try again.", + "placeholders": { + "STATUS": { + "content": "$1", + "example": "504" + } + } + }, + "api_timeout": { + "message": "The API timed out after $NUM$ seconds. Click to try again.", + "placeholders": { + "NUM": { + "content": "$1", + "example": "15" + } + } + }, + "action_unsave": { + "message": "unsave" + }, + "action_save": { + "message": "save" + }, + "action_unhide": { + "message": "unhide" + }, + "action_hide": { + "message": "hide" + }, + "action_share": { + "message": "share" + }, + "report_confirm": { + "message": "are you sure? $BEGIN_LINK_YES$yes$END_LINK_YES$/$BEGIN_LINK_NO$no$END_LINK_NO$", + "placeholders": { + "BEGIN_LINK_YES": { + "content": "" + }, + "END_LINK_YES": { + "content": "" + }, + "BEGIN_LINK_NO": { + "content": "" + }, + "END_LINK_NO": { + "content": "" + } + } + }, + "action_report": { + "message": "report" + }, + "action_reported": { + "message": "reported!" + }, + "button_submit": { + "message": "submit" + }, + "button_hide": { + "message": "hide this form" + }, + "error_empty": { + "message": "There needs to be something here." + }, + "loading_api": { + "message": "Loading data from the API..." + }, + "loading_cache": { + "message": "Loading data from the cache..." + }, + "loading_cache": { + "message": "Cannot create list for a URL that has not been cached." + }, + "score": { + "message": "$UPS$ upvotes, $DOWNS$ downvotes.", + "placeholders": { + "UPS": { + "content": "$1", + "example": "435" + }, + "DOWNS": { + "content": "$2", + "example": "243" + } + } + }, + "view_on_reddit": { + "message": "View this post on $REDDIT$", + "placeholders": { + "REDDIT": { + "content": "reddit" + } + } + }, + "submitted_when": { + "message": "submitted $TIME$", + "placeholders": { + "TIME": { + "content": "$1", + "example": "an hour ago" + } + } + }, + "by": { + "message": "by" + }, + "to": { + "message": "to" + }, + "add_comment_zero": { + "message": "add to the one comment" + }, + "add_comment_one": { + "message": "add a comment" + }, + "add_comment_many": { + "message": "add to the $NUM$ comments", + "placeholders": { + "NUM": { + "content": "$1", + "example": "42" + } + } + }, + "leave_comment": { + "message": "Leave a comment" + }, + "stale_posts_hiding": { + "message": "Hiding $NUM$ stale posts. $BEGIN_LINK_SHOW$Show them now$END_LINK_SHOW, or visit the $BEGIN_LINK_OPTIONS$options page$END_LINK_OPTIONS$ to change your Fresh Content preferences.", + "placeholders": { + "NUM": { + "content": "$1", + "example": "4" + }, + "BEGIN_LINK_SHOW": { + "content": "" + }, + "END_LINK_SHOW": { + "content": "" + }, + "BEGIN_LINK_OPTIONS": { + "content": "" + }, + "END_LINK_OPTIONS": { + "content": "" + } + } + }, + "stale_posts_showing": { + "message": "Showing stale posts. Visit the $BEGIN_LINK_OPTIONS$options page$END_LINK_OPTIONS$ to change your Fresh Content preferences.", + "placeholders": { + "BEGIN_LINK_OPTIONS": { + "content": "" + }, + "END_LINK_OPTIONS": { + "content": "" + } + } + } +} diff --git a/js/common.js b/js/common.js index c7e24b7..192f2ad 100644 --- a/js/common.js +++ b/js/common.js @@ -78,20 +78,20 @@ MHUtils.prototype.forEach = function (array, action) { // long ago the date represents. MHUtils.prototype.prettyDate = function (date_str) { var time_formats = [ - [60, 'just now', 1], // 60 - [120, '1 minute ago', '1 minute from now'], // 60*2 + [60, 'just_now', 1], // 60 + [120, 'a_minute_ago', 'a_minute_from_now'], // 60*2 [3600, 'minutes', 60], // 60*60, 60 - [7200, '1 hour ago', '1 hour from now'], // 60*60*2 + [7200, 'an_hour_ago', 'an_hour_from_now'], // 60*60*2 [86400, 'hours', 3600], // 60*60*24, 60*60 [172800, 'yesterday', 'tomorrow'], // 60*60*24*2 [604800, 'days', 86400], // 60*60*24*7, 60*60*24 - [1209600, 'last week', 'next week'], // 60*60*24*7*4*2 + [1209600, 'last_week', 'next_week'], // 60*60*24*7*4*2 [2419200, 'weeks', 604800], // 60*60*24*7*4, 60*60*24*7 - [4838400, 'last month', 'next month'], // 60*60*24*7*4*2 + [4838400, 'last_month', 'next_month'], // 60*60*24*7*4*2 [29030400, 'months', 2419200], // 60*60*24*7*4*12, 60*60*24*7*4 - [58060800, 'last year', 'next year'], // 60*60*24*7*4*12*2 + [58060800, 'last_year', 'next_year'], // 60*60*24*7*4*12*2 [2903040000, 'years', 29030400], // 60*60*24*7*4*12*100, 60*60*24*7*4*12 - [5806080000, 'last century', 'next century'], // 60*60*24*7*4*12*100*2 + [5806080000, 'last_century', 'next_century'], // 60*60*24*7*4*12*100*2 [58060800000, 'centuries', 2903040000] // 60*60*24*7*4*12*100*20, 60*60*24*7*4*12*100 ]; var time = ('' + date_str).replace(/-/g,"/").replace(/[TZ]/g," "); @@ -101,15 +101,15 @@ MHUtils.prototype.prettyDate = function (date_str) { var token = 'ago', list_choice = 1; if (seconds < 0) { seconds = Math.abs(seconds); - token = 'from now'; + token = 'from_now'; list_choice = 2; } var i = 0, format; while (format = time_formats[i++]) if (seconds < format[0]) { if (typeof format[2] == 'string') - return format[list_choice]; + return chrome.i18n.getMessage(format[list_choice]); else - return Math.floor(seconds / format[2]) + ' ' + format[1] + ' ' + token; + return chrome.i18n.getMessage(format[1] + '_' + token, Math.floor(seconds / format[2]).toString()); } return time; }; @@ -170,7 +170,7 @@ BrowserAction.prototype.setBadgeDefaults = function (tabId) { BrowserAction.prototype.setBadgeIgnore = function (tabId) { chrome.browserAction.setIcon({'path': '/pix/alien-fade.png', 'tabId': tabId}); chrome.browserAction.setBadgeText({'text': '', 'tabId': tabId}); - chrome.browserAction.setTitle({'title': 'Mostly Harmless is not activated for this page. Click to activate.', 'tabId': tabId}); + chrome.browserAction.setTitle({'title': chrome.i18n.getMessage('not_activated'), 'tabId': tabId}); chrome.browserAction.setPopup({popup: '', tabId: tabId}); chrome.browserAction.onClicked.addListener(function(tab) { reddit.getInfo(tab.url, tab.id); @@ -188,7 +188,7 @@ BrowserAction.prototype.setBadgeIgnore = function (tabId) { BrowserAction.prototype.setBadgeLoading = function (tabId) { chrome.browserAction.setIcon({'path': '/pix/alien.png', 'tabId': tabId}); chrome.browserAction.setBadgeText({'text': '', 'tabId': tabId}); - chrome.browserAction.setTitle({'title': 'Loading data...', 'tabId': tabId}); + chrome.browserAction.setTitle({'title': chrome.i18n.getMessage('loading'), 'tabId': tabId}); chrome.browserAction.setPopup({popup: '', tabId: tabId}); return true; }; @@ -229,17 +229,17 @@ BrowserAction.prototype.setBadgeFor = function (url, tabId) { if (cachedPosts.isCommentsPage === true) { chrome.browserAction.setBadgeText({'text': '...', 'tabId': tabId}); - chrome.browserAction.setTitle({'title': 'You are currently viewing the comments for this page.', 'tabId': tabId}); + chrome.browserAction.setTitle({'title': chrome.i18n.getMessage('viewing_comments'), 'tabId': tabId}); chrome.browserAction.setBadgeBackgroundColor({'color': [95, 153, 207, 255], 'tabId': tabId}); chrome.browserAction.setPopup({popup: '/html/popup.html', tabId: tabId}); } else if (cachedPosts.count === 0) { chrome.browserAction.setBadgeText({'text': '+', 'tabId': tabId}); - chrome.browserAction.setTitle({'title': 'Submit this page.', 'tabId': tabId}); + chrome.browserAction.setTitle({'title': chrome.i18n.getMessage('submit_page'), 'tabId': tabId}); chrome.browserAction.setBadgeBackgroundColor({'color': [0, 0, 0, 255], 'tabId': tabId}); chrome.browserAction.setPopup({popup: '/html/popup.html', tabId: tabId}); } else { chrome.browserAction.setBadgeText({'text': cachedPosts.count.toString(), 'tabId': tabId}); - chrome.browserAction.setTitle({'title': 'This page has been submitted ' + cachedPosts.count.toString() + ' times.', 'tabId': tabId}); + chrome.browserAction.setTitle({'title': chrome.i18n.getMessage('submitted_num_times', cachedPosts.count.toString()), 'tabId': tabId}); chrome.browserAction.setBadgeBackgroundColor({'color': [255, 69, 0, 255], 'tabId': tabId}); chrome.browserAction.setPopup({popup: '/html/popup.html', tabId: tabId}); } @@ -284,7 +284,7 @@ RedditAPI.prototype.apiTransmit = function (type, url, data, cback) { if (req.readyState === 4) { if (req.status === 200) { if (JSON.parse(req.responseText).jquery && JSON.parse(req.responseText).jquery[3][3][0] === '.error.USER_REQUIRED') { - throw 'You have to be logged in to do that. Click to open the login page.'; + throw chrome.i18n.getMessage('login'); } clearTimeout(apiTimeout); @@ -294,14 +294,14 @@ RedditAPI.prototype.apiTransmit = function (type, url, data, cback) { } return JSON.parse(req.responseText); } else { - throw 'API Error. HTTP Status: ' + req.status + '. Try again?'; + throw chrome.i18n.getMessage('api_error', req.status.toString()); } } } function handleTimeout () { req.abort(); - throw 'API Timeout after ' + settings.get('timeoutLength') + ' seconds. Click to try again.'; + throw chrome.i18n.getMessage('api_timeout', settings.get('timeoutLength').toString()); } req = new XMLHttpRequest(); @@ -356,14 +356,14 @@ RedditAPI.prototype.getInfo = function (url, tabId) { button.setBadgeFor(url, tabId); return true; } else { - button.setBadgeError(tabId, 'API Error. HTTP Status: ' + req.status + '. Click to try again.'); + button.setBadgeError(tabId, chrome.i18n.getMessage('api_error', req.status.toString())); } } } function handleTimeout () { req.abort(); - button.setBadgeError(tabId, 'API Timeout after ' + settings.get('timeoutLength') + ' seconds. Click to try again.'); + button.setBadgeError(tabId, chrome.i18n.getMessage('api_timeout', settings.get('timeoutLength').toString())); } button.setBadgeLoading(tabId); @@ -484,7 +484,7 @@ RedditAPI.prototype.savePost = function (e) { listItem.setAttribute('data-saved', 'true'); listItem.className.replace(/\bsaved\b/,''); listItem.className += ' unsave'; - e.srcElement.innerHTML = 'unsave'; + e.srcElement.innerHTML = chrome.i18n.getMessage('action_unsave'); e.srcElement.onclick = function (event) {reddit.unsavePost(event)}; oldCache.posts[fullName].data.saved = true; cache.set(url, oldCache); @@ -512,7 +512,7 @@ RedditAPI.prototype.unsavePost = function (e) { listItem.setAttribute('data-saved', 'false'); listItem.className.replace(/\bunsave\b/,''); listItem.className += ' saved'; - e.srcElement.innerHTML = 'save'; + e.srcElement.innerHTML = chrome.i18n.getMessage('action_save'); e.srcElement.onclick = function (event) {reddit.savePost(event)}; oldCache.posts[fullName].data.saved = false; cache.set(url, oldCache); @@ -538,7 +538,7 @@ RedditAPI.prototype.hidePost = function (e) { formData.append('id', fullName); formData.append('uh', cache.get('modhash')); listItem.setAttribute('data-hidestatus', 'true'); - e.srcElement.innerHTML = 'unhide'; + e.srcElement.innerHTML = chrome.i18n.getMessage('action_unhide'); e.srcElement.onclick = function (event) {reddit.unhidePost(event)}; oldCache.posts[fullName].data.hidden = true; cache.set(url, oldCache); @@ -564,7 +564,7 @@ RedditAPI.prototype.unhidePost = function (e) { formData.append('id', fullName); formData.append('uh', cache.get('modhash')); listItem.setAttribute('data-hidestatus', 'false'); - e.srcElement.innerHTML = 'hide'; + e.srcElement.innerHTML = chrome.i18n.getMessage('action_hide'); e.srcElement.onclick = function (event) {reddit.hidePost(event)}; oldCache.posts[fullName].data.hidden = false; cache.set(url, oldCache); @@ -581,7 +581,7 @@ RedditAPI.prototype.unhidePost = function (e) { RedditAPI.prototype.confirmReport = function (e) { e.srcElement.className = 'report-confirm'; e.srcElement.removeAttribute('onclick'); - e.srcElement.innerHTML = 'are you sure? yes/no'; + e.srcElement.innerHTML = chrome.i18n.getMessage('report_confirm'); return true; }; @@ -595,7 +595,7 @@ RedditAPI.prototype.confirmReport = function (e) { RedditAPI.prototype.denyReport = function (e) { e.srcElement.parentNode.className = 'report'; e.srcElement.parentNode.setAttribute('onclick', 'reddit.confirmReport(event)'); - e.srcElement.parentNode.innerHTML = 'report'; + e.srcElement.parentNode.innerHTML = chrome.i18n.getMessage('action_report'); return true; }; @@ -624,7 +624,7 @@ RedditAPI.prototype.reportPost = function (e) { oldCache.posts[fullName].data.hidden = true; cache.set(url, oldCache); listItem.setAttribute('data-reportstatus', 'true'); - e.srcElement.parentNode.innerHTML = 'reported!'; + e.srcElement.parentNode.innerHTML = chrome.i18n.getMessage('action_reported'); }; /** @@ -641,8 +641,8 @@ RedditAPI.prototype.submitComment = function (e) { var url, oldCache; status.innerHTML = ''; - submitButton.innerHTML = 'saved'; - cancelButton.innerHTML = 'hide this form'; + submitButton.innerHTML = chrome.i18n.getMessage('button_submit'); + cancelButton.innerHTML = chrome.i18n.getMessage('button_hide'); submitButton.setAttribute('disabled'); textarea.setAttribute('readonly'); textarea.onkeyup = function () {return true;}; @@ -663,7 +663,7 @@ RedditAPI.prototype.submitComment = function (e) { comment = settings.get('shamelessPlug') ? textarea.value + '\n\n*Posted from [Mostly Harmless](http://kerrick.github.com/Mostly-Harmless), a Google Chrome extension for awesome redditors.*' : textarea.value; if (textarea.value === '') { - status.innerHTML = 'There needs to be something here.'; + status.innerHTML = chrome.i18n.getMessage('error_empty'); } else { formData = new FormData(); formData.append('thing_id', fullName); @@ -703,10 +703,10 @@ function Background() { Background.prototype.prepareBrowserAction = function (tabId, info, tab) { if (info.status === 'loading') { if (cache.get(tab.url) === undefined || cache.get(tab.url).cacheDate - utils.epoch() < -60 * settings.get('cacheTime')) { - console.log('Grabbing data from the API...'); + console.log(chrome.i18n.getMessage('loading_api')); reddit.getInfo(tab.url, tabId); } else { - console.log('Grabbing data from the cache...'); + console.log(chrome.i18n.getMessage('loading_cache')); button.setBadgeFor(tab.url, tabId); } } @@ -736,7 +736,7 @@ Popup.prototype.createListHTML = function (url) { var listHTML, staleCounter; if (cache.get(url) === undefined) { - throw 'Cannot create list HTML for a non-cached URL.'; + throw chrome.i18n.getMessage('error_not_cached'); } listHTML = '
    '; @@ -764,34 +764,44 @@ Popup.prototype.createListHTML = function (url) { listHTML += '
  1. '; listHTML += '
    '; listHTML += ''; - listHTML += '' + data.score + ''; + listHTML += '' + data.score + ''; listHTML += ''; listHTML += '
    '; - listHTML += ''; + listHTML += ''; listHTML += '' + data.title + ''; listHTML += ''; listHTML += '
    '; - listHTML += '' + data.title + ' '; + listHTML += '' + data.title + ' '; listHTML += '(' + data.domain + ')'; listHTML += '
    '; - listHTML += 'submitted ' + utils.prettyDate(utils.ISODateString(new Date(data.created_utc * 1000))) + ' by '; - listHTML += '' + data.author + ' to '; + listHTML += '' + chrome.i18n.getMessage('submitted_when', utils.prettyDate(utils.ISODateString(new Date(data.created_utc * 1000)))) + ' ' + chrome.i18n.getMessage('by') + ' '; + listHTML += '' + data.author + ' ' + chrome.i18n.getMessage('to') + ' '; listHTML += '' + data.subreddit + ''; listHTML += '
    '; listHTML += '
    '; - listHTML += 'add to the ' + data.num_comments + ' comments'; - listHTML += ''; - listHTML += '' + saveText + ''; - listHTML += '' + hiddenText + ''; - listHTML += 'report'; + switch (data.num_comments) { + case 0: + listHTML += '' + chrome.i18n.getMessage('add_comment_zero') + ''; + break; + case 1: + listHTML += '' + chrome.i18n.getMessage('add_comment_zero') + ''; + break; + default: + listHTML += '' + chrome.i18n.getMessage('add_comment_zero', data.num_comments.toString()) + ''; + break; + } + listHTML += ''; + listHTML += '' + chrome.i18n.getMessage('action_save') + ''; + listHTML += '' + chrome.i18n.getMessage('action_hide') + ''; + listHTML += '' + chrome.i18n.getMessage('action_report') + ''; listHTML += '
    '; listHTML += '
    '; listHTML += '
    '; listHTML += '
    '; - listHTML += 'Leave a comment'; + listHTML += '' + chrome.i18n.getMessage('leave_comment') + ''; listHTML += ''; - listHTML += ''; - listHTML += ''; + listHTML += ''; + listHTML += ''; listHTML += ''; listHTML += '
    '; listHTML += '
    '; @@ -801,7 +811,7 @@ Popup.prototype.createListHTML = function (url) { listHTML += '
' if (staleCounter > 0) { - listHTML += '
Hiding ' + staleCounter.toString() + ' stale posts. Show them now, or visit the options page to change your Fresh Content preferences.
'; + listHTML += '
' + chrome.i18n.getMessage('stale_posts_hiding', staleCounter.toString()) + '
'; } return listHTML; @@ -829,7 +839,7 @@ Popup.prototype.showStalePosts = function () { var stalePosts; stalePosts = document.getElementsByClassName('stale'); - document.getElementById('information').innerHTML = 'Showing stale posts. Visit the options page to change your Fresh Content preferences.'; + document.getElementById('information').innerHTML = chrome.i18n.getMessage('stale_posts_showing'); while (stalePosts.length > 0) { stalePosts[0].className = 'stale-shown'; diff --git a/manifest.json b/manifest.json index b9c1452..2ba8849 100644 --- a/manifest.json +++ b/manifest.json @@ -11,5 +11,6 @@ "tabs" ], "background_page": "html/background.html", - "options_page": "fancy-settings/index.html" + "options_page": "fancy-settings/index.html", + "default_locale": "en_US" } \ No newline at end of file