Skip to content
This repository has been archived by the owner on May 30, 2023. It is now read-only.

feat: support i18n #50

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions i18n/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"i-message": "message"
}
3 changes: 3 additions & 0 deletions i18n/zh.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"i-message": "信息"
}
13 changes: 10 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
<link href="https://fonts.googleapis.com/css?family=Roboto&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/assets/site.css" />
<script src="/scripts/jquery-3.4.1.min.js"></script>
<script src="/scripts/jquery.i18n.js"></script>
<script src="/scripts/jquery.i18n.messagestore.js"></script>
<script src="/scripts/jquery.i18n.fallbacks.js"></script>
<script src="/scripts/jquery.i18n.parser.js"></script>
<script src="/scripts/jquery.i18n.emitter.js"></script>
<script src="/scripts/jquery.i18n.language.js"></script>
<script src="/scripts/main.js"></script>

<!-- Google Tag Manager -->
Expand Down Expand Up @@ -80,6 +86,7 @@
<a target="_blank" href="https://github.com/DimensionDev/Maskbook">Source Code</a>
<a target="_blank" href="https://news.mask.io">Blog</a>
<a class="link-button" href="/install">Install</a>
<a data-i18n="i-message"></a>
</nav>
</section>
</section>
Expand Down Expand Up @@ -504,10 +511,10 @@ <h4>Get latest news, keep updated.</h4>
<footer>
<p class="description text-secondary">I thought what I’d do was, I’d pretend I was one of those deaf-mutes.</p>
<section class="content">
<nav class="locale" hidden>
<a>English</a>
<nav class="locale">
<a id="i18n-en">English</a>
<a>繁体中文</a>
<a>简体中文</a>
<a id="i18n-zh">简体中文</a>
</nav>
</section>
</footer>
Expand Down
168 changes: 168 additions & 0 deletions scripts/jquery.i18n.emitter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/*!
* jQuery Internationalization library
*
* Copyright (C) 2011-2013 Santhosh Thottingal, Neil Kandalgaonkar
*
* jquery.i18n is dual licensed GPLv2 or later and MIT. You don't have to do
* anything special to choose one license or the other and you don't have to
* notify anyone which license you are using. You are free to use
* UniversalLanguageSelector in commercial projects as long as the copyright
* header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
*
* @licence GNU General Public Licence 2.0 or later
* @licence MIT License
*/

( function ( $ ) {
'use strict';

var MessageParserEmitter = function () {
this.language = $.i18n.languages[ String.locale ] || $.i18n.languages[ 'default' ];
};

MessageParserEmitter.prototype = {
constructor: MessageParserEmitter,

/**
* (We put this method definition here, and not in prototype, to make
* sure it's not overwritten by any magic.) Walk entire node structure,
* applying replacements and template functions when appropriate
*
* @param {Mixed} node abstract syntax tree (top node or subnode)
* @param {Array} replacements for $1, $2, ... $n
* @return {Mixed} single-string node or array of nodes suitable for
* jQuery appending.
*/
emit: function ( node, replacements ) {
var ret, subnodes, operation,
messageParserEmitter = this;

switch ( typeof node ) {
case 'string':
case 'number':
ret = node;
break;
case 'object':
// node is an array of nodes
subnodes = $.map( node.slice( 1 ), function ( n ) {
return messageParserEmitter.emit( n, replacements );
} );

operation = node[ 0 ].toLowerCase();

if ( typeof messageParserEmitter[ operation ] === 'function' ) {
ret = messageParserEmitter[ operation ]( subnodes, replacements );
} else {
throw new Error( 'unknown operation "' + operation + '"' );
}

break;
case 'undefined':
// Parsing the empty string (as an entire expression, or as a
// paramExpression in a template) results in undefined
// Perhaps a more clever parser can detect this, and return the
// empty string? Or is that useful information?
// The logical thing is probably to return the empty string here
// when we encounter undefined.
ret = '';
break;
default:
throw new Error( 'unexpected type in AST: ' + typeof node );
}

return ret;
},

/**
* Parsing has been applied depth-first we can assume that all nodes
* here are single nodes Must return a single node to parents -- a
* jQuery with synthetic span However, unwrap any other synthetic spans
* in our children and pass them upwards
*
* @param {Array} nodes Mixed, some single nodes, some arrays of nodes.
* @return {string}
*/
concat: function ( nodes ) {
var result = '';

$.each( nodes, function ( i, node ) {
// strings, integers, anything else
result += node;
} );

return result;
},

/**
* Return escaped replacement of correct index, or string if
* unavailable. Note that we expect the parsed parameter to be
* zero-based. i.e. $1 should have become [ 0 ]. if the specified
* parameter is not found return the same string (e.g. "$99" ->
* parameter 98 -> not found -> return "$99" ) TODO throw error if
* nodes.length > 1 ?
*
* @param {Array} nodes One element, integer, n >= 0
* @param {Array} replacements for $1, $2, ... $n
* @return {string} replacement
*/
replace: function ( nodes, replacements ) {
var index = parseInt( nodes[ 0 ], 10 );

if ( index < replacements.length ) {
// replacement is not a string, don't touch!
return replacements[ index ];
} else {
// index not found, fallback to displaying variable
return '$' + ( index + 1 );
}
},

/**
* Transform parsed structure into pluralization n.b. The first node may
* be a non-integer (for instance, a string representing an Arabic
* number). So convert it back with the current language's
* convertNumber.
*
* @param {Array} nodes List [ {String|Number}, {String}, {String} ... ]
* @return {string} selected pluralized form according to current
* language.
*/
plural: function ( nodes ) {
var count = parseFloat( this.language.convertNumber( nodes[ 0 ], 10 ) ),
forms = nodes.slice( 1 );

return forms.length ? this.language.convertPlural( count, forms ) : '';
},

/**
* Transform parsed structure into gender Usage
* {{gender:gender|masculine|feminine|neutral}}.
*
* @param {Array} nodes List [ {String}, {String}, {String} , {String} ]
* @return {string} selected gender form according to current language
*/
gender: function ( nodes ) {
var gender = nodes[ 0 ],
forms = nodes.slice( 1 );

return this.language.gender( gender, forms );
},

/**
* Transform parsed structure into grammar conversion. Invoked by
* putting {{grammar:form|word}} in a message
*
* @param {Array} nodes List [{Grammar case eg: genitive}, {String word}]
* @return {string} selected grammatical form according to current
* language.
*/
grammar: function ( nodes ) {
var form = nodes[ 0 ],
word = nodes[ 1 ];

return word && form && this.language.convertGrammar( word, form );
}
};

$.extend( $.i18n.parser.emitter, new MessageParserEmitter() );
}( jQuery ) );
Loading