This commit is contained in:
Vinjor 2024-11-29 10:09:00 +08:00
commit 93f0567c8f
16 changed files with 938 additions and 0 deletions

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

4
.idea/encodings.xml Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8" />
</project>

9
.idea/i18n_language.iml Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -0,0 +1,36 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="JavaDoc" enabled="true" level="WARNING" enabled_by_default="true">
<option name="TOP_LEVEL_CLASS_OPTIONS">
<value>
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
<option name="REQUIRED_TAGS" value="" />
</value>
</option>
<option name="INNER_CLASS_OPTIONS">
<value>
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
<option name="REQUIRED_TAGS" value="" />
</value>
</option>
<option name="METHOD_OPTIONS">
<value>
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
<option name="REQUIRED_TAGS" value="@return@param@throws or @exception" />
</value>
</option>
<option name="FIELD_OPTIONS">
<value>
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
<option name="REQUIRED_TAGS" value="" />
</value>
</option>
<option name="IGNORE_DEPRECATED" value="false" />
<option name="IGNORE_JAVADOC_PERIOD" value="true" />
<option name="IGNORE_DUPLICATED_THROWS" value="false" />
<option name="IGNORE_POINT_TO_ITSELF" value="false" />
<option name="myAdditionalJavadocTags" value="date" />
</inspection_tool>
</profile>
</component>

6
.idea/misc.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/i18n_language.iml" filepath="$PROJECT_DIR$/i18n_language.iml" />
</modules>
</component>
</project>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
</set>
</option>
</component>
</project>

8
i18n_language.iml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

38
index.html Normal file
View File

@ -0,0 +1,38 @@
<!doctype html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>国际化样例</title>
</head>
<body>
<form>
<select class="lan_select">
<option class="lan_zh" value="zh_CN" selected>中文</option>
<option class="lan_en" value="en_US">英文</option>
</select>
</form>
<!--文本自动翻译demo区域----start -->
<form action="">
<label data-translate="name" for="name">姓名:</label><input data-translate-placeholder="name_placeholder" type="text" placeholder="" id="name" name="name" required><br>
<label data-translate="tel" for="phone">电话号码:</label><input data-translate-placeholder="tel_placeholder" type="tel" placeholder="" id="phone" name="phone" required><br>
<label data-translate="email" for="email">电子邮箱:</label><input data-translate-placeholder="email_placeholder" type="email" placeholder="" id="email" name="email"><br>
<label data-translate="address" for="address">地址:</label><input data-translate-placeholder="address_placeholder" type="text" placeholder="" id="address" name="address"><br>
<label data-translate="choose">选择器:</label><select id="mySelect"></select><br>
<button data-translate="save" type="button">保存</button>
<button data-translate="reset" type="button">重置</button>
</form>
<!--文本自动翻译demo区域----end -->
<!--主动翻译demo区域----start -->
<!--<label for="name">获取当前语言包下指定的key的翻译</label><input type="text" value="test1" id="data_key" name="data_key" ><br>-->
<!--<button type="button" onclick="getKeyClick()">获取</button>-->
<!--<div id="data_key_text"></div>-->
<!--主动翻译demo区域----end -->
<script type="application/javascript" src="js/jquery-3.7.1.min.js"></script>
<script type="application/javascript" src="js/jquery.cookie.js"></script>
<script type="application/javascript" src="js/jquery.i18n.properties.js"></script>
<script type="application/javascript" src="js/language.js"></script>
</body>
</html>

2
js/jquery-3.7.1.min.js vendored Normal file

File diff suppressed because one or more lines are too long

117
js/jquery.cookie.js Normal file
View File

@ -0,0 +1,117 @@
/*!
* jQuery Cookie Plugin v1.4.1
* https://github.com/carhartl/jquery-cookie
*
* Copyright 2013 Klaus Hartl
* Released under the MIT license
*/
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// CommonJS
factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
var pluses = /\+/g;
function encode(s) {
return config.raw ? s : encodeURIComponent(s);
}
function decode(s) {
return config.raw ? s : decodeURIComponent(s);
}
function stringifyCookieValue(value) {
return encode(config.json ? JSON.stringify(value) : String(value));
}
function parseCookieValue(s) {
if (s.indexOf('"') === 0) {
// This is a quoted cookie as according to RFC2068, unescape...
s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
}
try {
// Replace server-side written pluses with spaces.
// If we can't decode the cookie, ignore it, it's unusable.
// If we can't parse the cookie, ignore it, it's unusable.
s = decodeURIComponent(s.replace(pluses, ' '));
return config.json ? JSON.parse(s) : s;
} catch(e) {}
}
function read(s, converter) {
var value = config.raw ? s : parseCookieValue(s);
return $.isFunction(converter) ? converter(value) : value;
}
var config = $.cookie = function (key, value, options) {
// Write
if (value !== undefined && !$.isFunction(value)) {
options = $.extend({}, config.defaults, options);
if (typeof options.expires === 'number') {
var days = options.expires, t = options.expires = new Date();
t.setTime(+t + days * 864e+5);
}
return (document.cookie = [
encode(key), '=', stringifyCookieValue(value),
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
options.path ? '; path=' + options.path : '',
options.domain ? '; domain=' + options.domain : '',
options.secure ? '; secure' : ''
].join(''));
}
// Read
var result = key ? undefined : {};
// To prevent the for loop in the first place assign an empty array
// in case there are no cookies at all. Also prevents odd result when
// calling $.cookie().
var cookies = document.cookie ? document.cookie.split('; ') : [];
for (var i = 0, l = cookies.length; i < l; i++) {
var parts = cookies[i].split('=');
var name = decode(parts.shift());
var cookie = parts.join('=');
if (key && key === name) {
// If second argument (value) is a function it's a converter...
result = read(cookie, value);
break;
}
// Prevent storing a cookie that we couldn't decode.
if (!key && (cookie = read(cookie)) !== undefined) {
result[name] = cookie;
}
}
return result;
};
config.defaults = {};
$.removeCookie = function (key, options) {
if ($.cookie(key) === undefined) {
return false;
}
// Must not alter options, thus extending a fresh object...
$.cookie(key, '', $.extend({}, options, { expires: -1 }));
return !$.cookie(key);
};
}));

View File

@ -0,0 +1,506 @@
/******************************************************************************
* jquery.i18n.properties
*
* Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and
* MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses.
*
* @version 1.2.7
* @url https://github.com/jquery-i18n-properties/jquery-i18n-properties
* @inspiration Localisation assistance for jQuery (http://keith-wood.name/localisation.html)
* by Keith Wood (kbwood{at}iinet.com.au) June 2007
*
*****************************************************************************/
(function ($) {
$.i18n = {};
/**
* Map holding bundle keys if mode is 'map' or 'both'. Values of this can also be an
* Object, in which case the key is a namespace.
*/
$.i18n.map = {};
var debug = function (message) {
window.console && console.log('i18n::' + message);
};
/**
* Load and parse message bundle files (.properties),
* making bundles keys available as javascript variables.
*
* i18n files are named <name>.js, or <name>_<language>.js or <name>_<language>_<country>.js
* Where:
* The <language> argument is a valid ISO Language Code. These codes are the lower-case,
* two-letter codes as defined by ISO-639. You can find a full list of these codes at a
* number of sites, such as: http://www.loc.gov/standards/iso639-2/englangn.html
* The <country> argument is a valid ISO Country Code. These codes are the upper-case,
* two-letter codes as defined by ISO-3166. You can find a full list of these codes at a
* number of sites, such as: http://www.iso.ch/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html
*
* Sample usage for a bundles/Messages.properties bundle:
* $.i18n.properties({
* name: 'Messages',
* language: 'en_US',
* path: 'bundles'
* });
* @param name (string/string[], optional) names of file to load (eg, 'Messages' or ['Msg1','Msg2']). Defaults to "Messages"
* @param language (string, optional) language/country code (eg, 'en', 'en_US', 'pt_BR'). if not specified, language reported by the browser will be used instead.
* @param path (string, optional) path of directory that contains file to load
* @param mode (string, optional) whether bundles keys are available as JavaScript variables/functions or as a map (eg, 'vars' or 'map')
* @param debug (boolean, optional) whether debug statements are logged at the console
* @param cache (boolean, optional) whether bundles should be cached by the browser, or forcibly reloaded on each page load. Defaults to false (i.e. forcibly reloaded)
* @param encoding (string, optional) the encoding to request for bundles. Property file resource bundles are specified to be in ISO-8859-1 format. Defaults to UTF-8 for backward compatibility.
* @param callback (function, optional) callback function to be called after script is terminated
*/
$.i18n.properties = function (settings) {
var defaults = {
name: 'Messages',
language: '',
path: '',
namespace: null,
mode: 'vars',
cache: false,
debug: false,
encoding: 'UTF-8',
async: false,
callback: null
};
settings = $.extend(defaults, settings);
if (settings.namespace && typeof settings.namespace == 'string') {
// A namespace has been supplied, initialise it.
if (settings.namespace.match(/^[a-z]*$/)) {
$.i18n.map[settings.namespace] = {};
} else {
debug('Namespaces can only be lower case letters, a - z');
settings.namespace = null;
}
}
// Ensure a trailing slash on the path
if (!settings.path.match(/\/$/)) settings.path += '/';
// Try to ensure that we have at a least a two letter language code
settings.language = this.normaliseLanguageCode(settings);
// Ensure an array
var files = (settings.name && settings.name.constructor === Array) ? settings.name : [settings.name];
// A locale is at least a language code which means at least two files per name. If
// we also have a country code, thats an extra file per name.
settings.totalFiles = (files.length * 2) + ((settings.language.length >= 5) ? files.length : 0);
if (settings.debug) {
debug('totalFiles: ' + settings.totalFiles);
}
settings.filesLoaded = 0;
files.forEach(function (file) {
var defaultFileName, shortFileName, longFileName, fileNames;
// 1. load base (eg, Messages.properties)
defaultFileName = settings.path + file + '.properties';
// 2. with language code (eg, Messages_pt.properties)
var shortCode = settings.language.substring(0, 2);
shortFileName = settings.path + file + '_' + shortCode + '.properties';
// 3. with language code and country code (eg, Messages_pt_BR.properties)
if (settings.language.length >= 5) {
var longCode = settings.language.substring(0, 5);
longFileName = settings.path + file + '_' + longCode + '.properties';
fileNames = [defaultFileName, shortFileName, longFileName];
} else {
fileNames = [defaultFileName, shortFileName];
}
loadAndParseFiles(fileNames, settings);
});
// call callback
if (settings.callback && !settings.async) {
settings.callback();
}
}; // properties
/**
* When configured with mode: 'map', allows access to bundle values by specifying its key.
* Eg, jQuery.i18n.prop('com.company.bundles.menu_add')
*/
$.i18n.prop = function (key /* Add parameters as function arguments as necessary */) {
var args = [].slice.call(arguments);
var phvList, namespace;
if (args.length == 2) {
if ($.isArray(args[1])) {
// An array was passed as the second parameter, so assume it is the list of place holder values.
phvList = args[1];
} else if (typeof args[1] === 'object') {
// Second argument is an options object {namespace: 'mynamespace', replacements: ['egg', 'nog']}
namespace = args[1].namespace;
var replacements = args[1].replacements;
args.splice(-1, 1);
if (replacements) {
Array.prototype.push.apply(args, replacements);
}
}
}
var value = (namespace) ? $.i18n.map[namespace][key] : $.i18n.map[key];
if (value === null) {
return '[' + ((namespace) ? namespace + '#' + key : key) + ']';
}
// Place holder replacement
/**
* Tested with:
* test.t1=asdf ''{0}''
* test.t2=asdf '{0}' '{1}'{1}'zxcv
* test.t3=This is \"a quote" 'a''{0}''s'd{fgh{ij'
* test.t4="'''{'0}''" {0}{a}
* test.t5="'''{0}'''" {1}
* test.t6=a {1} b {0} c
* test.t7=a 'quoted \\ s\ttringy' \t\t x
*
* Produces:
* test.t1, p1 ==> asdf 'p1'
* test.t2, p1 ==> asdf {0} {1}{1}zxcv
* test.t3, p1 ==> This is "a quote" a'{0}'sd{fgh{ij
* test.t4, p1 ==> "'{0}'" p1{a}
* test.t5, p1 ==> "'{0}'" {1}
* test.t6, p1 ==> a {1} b p1 c
* test.t6, p1, p2 ==> a p2 b p1 c
* test.t6, p1, p2, p3 ==> a p2 b p1 c
* test.t7 ==> a quoted \ s tringy x
*/
var i;
if (typeof(value) == 'string') {
// Handle escape characters. Done separately from the tokenizing loop below because escape characters are
// active in quoted strings.
i = 0;
while ((i = value.indexOf('\\', i)) != -1) {
if (value.charAt(i + 1) == 't') {
value = value.substring(0, i) + '\t' + value.substring((i++) + 2); // tab
} else if (value.charAt(i + 1) == 'r') {
value = value.substring(0, i) + '\r' + value.substring((i++) + 2); // return
} else if (value.charAt(i + 1) == 'n') {
value = value.substring(0, i) + '\n' + value.substring((i++) + 2); // line feed
} else if (value.charAt(i + 1) == 'f') {
value = value.substring(0, i) + '\f' + value.substring((i++) + 2); // form feed
} else if (value.charAt(i + 1) == '\\') {
value = value.substring(0, i) + '\\' + value.substring((i++) + 2); // \
} else {
value = value.substring(0, i) + value.substring(i + 1); // Quietly drop the character
}
}
// Lazily convert the string to a list of tokens.
var arr = [], j, index;
i = 0;
while (i < value.length) {
if (value.charAt(i) == '\'') {
// Handle quotes
if (i == value.length - 1) {
value = value.substring(0, i); // Silently drop the trailing quote
} else if (value.charAt(i + 1) == '\'') {
value = value.substring(0, i) + value.substring(++i); // Escaped quote
} else {
// Quoted string
j = i + 2;
while ((j = value.indexOf('\'', j)) != -1) {
if (j == value.length - 1 || value.charAt(j + 1) != '\'') {
// Found start and end quotes. Remove them
value = value.substring(0, i) + value.substring(i + 1, j) + value.substring(j + 1);
i = j - 1;
break;
} else {
// Found a double quote, reduce to a single quote.
value = value.substring(0, j) + value.substring(++j);
}
}
if (j == -1) {
// There is no end quote. Drop the start quote
value = value.substring(0, i) + value.substring(i + 1);
}
}
} else if (value.charAt(i) == '{') {
// Beginning of an unquoted place holder.
j = value.indexOf('}', i + 1);
if (j == -1) {
i++; // No end. Process the rest of the line. Java would throw an exception
} else {
// Add 1 to the index so that it aligns with the function arguments.
index = parseInt(value.substring(i + 1, j));
if (!isNaN(index) && index >= 0) {
// Put the line thus far (if it isn't empty) into the array
var s = value.substring(0, i);
if (s !== "") {
arr.push(s);
}
// Put the parameter reference into the array
arr.push(index);
// Start the processing over again starting from the rest of the line.
i = 0;
value = value.substring(j + 1);
} else {
i = j + 1; // Invalid parameter. Leave as is.
}
}
} else {
i++;
}
} // while
// Put the remainder of the no-empty line into the array.
if (value !== "") {
arr.push(value);
}
value = arr;
// Make the array the value for the entry.
if (namespace) {
$.i18n.map[settings.namespace][key] = arr;
} else {
$.i18n.map[key] = arr;
}
}
if (value.length === 0) {
return "";
}
if (value.length == 1 && typeof(value[0]) == "string") {
return value[0];
}
var str = "";
for (i = 0, j = value.length; i < j; i++) {
if (typeof(value[i]) == "string") {
str += value[i];
} else if (phvList && value[i] < phvList.length) {
// Must be a number
str += phvList[value[i]];
} else if (!phvList && value[i] + 1 < args.length) {
str += args[value[i] + 1];
} else {
str += "{" + value[i] + "}";
}
}
return str;
};
function callbackIfComplete(settings) {
if (settings.debug) {
debug('callbackIfComplete()');
debug('totalFiles: ' + settings.totalFiles);
debug('filesLoaded: ' + settings.filesLoaded);
}
if (settings.async) {
if (settings.filesLoaded === settings.totalFiles) {
if (settings.callback) {
settings.callback();
}
}
}
}
function loadAndParseFiles(fileNames, settings) {
if (settings.debug) debug('loadAndParseFiles');
if (fileNames !== null && fileNames.length > 0) {
loadAndParseFile(fileNames[0], settings, function () {
fileNames.shift();
loadAndParseFiles(fileNames,settings);
});
} else {
callbackIfComplete(settings);
}
}
/** Load and parse .properties files */
function loadAndParseFile(filename, settings, nextFile) {
if (settings.debug) {
debug('loadAndParseFile(\'' + filename +'\')');
debug('totalFiles: ' + settings.totalFiles);
debug('filesLoaded: ' + settings.filesLoaded);
}
if (filename !== null && typeof filename !== 'undefined') {
$.ajax({
url: filename,
async: settings.async,
cache: settings.cache,
dataType: 'text',
success: function (data, status) {
if (settings.debug) {
debug('Succeeded in downloading ' + filename + '.');
debug(data);
}
parseData(data, settings);
nextFile();
},
error: function (jqXHR, textStatus, errorThrown) {
if (settings.debug) {
debug('Failed to download or parse ' + filename + '. errorThrown: ' + errorThrown);
}
if (jqXHR.status === 404) {
settings.totalFiles -= 1;
}
nextFile();
}
});
}
}
/** Parse .properties files */
function parseData(data, settings) {
var parsed = '';
var lines = data.split(/\n/);
var regPlaceHolder = /(\{\d+})/g;
var regRepPlaceHolder = /\{(\d+)}/g;
var unicodeRE = /(\\u.{4})/ig;
for (var i=0,j=lines.length;i<j;i++) {
var line = lines[i];
line = line.trim();
if (line.length > 0 && line.match("^#") != "#") { // skip comments
var pair = line.split('=');
if (pair.length > 0) {
/** Process key & value */
var name = decodeURI(pair[0]).trim();
var value = pair.length == 1 ? "" : pair[1];
// process multi-line values
while (value.search(/\\$/) != -1) {
value = value.substring(0, value.length - 1);
value += lines[++i].trimRight();
}
// Put values with embedded '='s back together
for (var s = 2; s < pair.length; s++) {
value += '=' + pair[s];
}
value = value.trim();
/** Mode: bundle keys in a map */
if (settings.mode == 'map' || settings.mode == 'both') {
// handle unicode chars possibly left out
var unicodeMatches = value.match(unicodeRE);
if (unicodeMatches) {
unicodeMatches.forEach(function (match) {
value = value.replace(match, unescapeUnicode(match));
});
}
// add to map
if (settings.namespace) {
$.i18n.map[settings.namespace][name] = value;
} else {
$.i18n.map[name] = value;
}
}
/** Mode: bundle keys as vars/functions */
if (settings.mode == 'vars' || settings.mode == 'both') {
value = value.replace(/"/g, '\\"'); // escape quotation mark (")
// make sure namespaced key exists (eg, 'some.key')
checkKeyNamespace(name);
// value with variable substitutions
if (regPlaceHolder.test(value)) {
var parts = value.split(regPlaceHolder);
// process function args
var first = true;
var fnArgs = '';
var usedArgs = [];
parts.forEach(function (part) {
if (regPlaceHolder.test(part) && (usedArgs.length === 0 || usedArgs.indexOf(part) == -1)) {
if (!first) {
fnArgs += ',';
}
fnArgs += part.replace(regRepPlaceHolder, 'v$1');
usedArgs.push(part);
first = false;
}
});
parsed += name + '=function(' + fnArgs + '){';
// process function body
var fnExpr = '"' + value.replace(regRepPlaceHolder, '"+v$1+"') + '"';
parsed += 'return ' + fnExpr + ';' + '};';
// simple value
} else {
parsed += name + '="' + value + '";';
}
} // END: Mode: bundle keys as vars/functions
} // END: if(pair.length > 0)
} // END: skip comments
}
eval(parsed);
settings.filesLoaded += 1;
}
/** Make sure namespace exists (for keys with dots in name) */
// TODO key parts that start with numbers quietly fail. i.e. month.short.1=Jan
function checkKeyNamespace(key) {
var regDot = /\./;
if (regDot.test(key)) {
var fullname = '';
var names = key.split(/\./);
for (var i=0,j=names.length;i<j;i++) {
var name = names[i];
if (i > 0) {
fullname += '.';
}
fullname += name;
if (eval('typeof ' + fullname + ' == "undefined"')) {
eval(fullname + '={};');
}
}
}
}
/** Ensure language code is in the format aa_AA. */
$.i18n.normaliseLanguageCode = function (settings) {
var lang = settings.language;
if (!lang || lang.length < 2) {
if (settings.debug) debug('No language supplied. Pulling it from the browser ...');
lang = (navigator.languages && navigator.languages.length > 0) ? navigator.languages[0]
: (navigator.language || navigator.userLanguage /* IE */ || 'en');
if (settings.debug) debug('Language from browser: ' + lang);
}
lang = lang.toLowerCase();
lang = lang.replace(/-/,"_"); // some browsers report language as en-US instead of en_US
if (lang.length > 3) {
lang = lang.substring(0, 3) + lang.substring(3).toUpperCase();
}
return lang;
};
/** Unescape unicode chars ('\u00e3') */
function unescapeUnicode(str) {
// unescape unicode codes
var codes = [];
var code = parseInt(str.substr(2), 16);
if (code >= 0 && code < Math.pow(2, 16)) {
codes.push(code);
}
// convert codes to text
return codes.reduce(function (acc, val) { return acc + String.fromCharCode(val); }, '');
}
}) (jQuery);

160
js/language.js Normal file
View File

@ -0,0 +1,160 @@
//网站默认语言标识
var languageKey = "zh_CN";
/*
设置一下网站支持的语言种类
zh_CN(中文简体)en_US(英语)
*/
var languageArray = ['zh_CN', 'en_US'];
/**
* 页面初始化执行方法
*/
$(document).ready(async function () {
//1.cookie是否存在
if ($.cookie("userLanguage")) {
languageKey = $.cookie("userLanguage");
} else {
//2.1 获取用户设置的浏览器语言
var webLanguage = $.i18n.normaliseLanguageCode({});
var charSize = $.inArray(webLanguage, languageArray);
if (charSize > -1) {
languageKey = webLanguage;
// 存到缓存中
$.cookie("userLanguage", webLanguage, {
expires: 7
});
} else {
//不支持的语言,使用默认中文
}
}
$(".lan_select").val(languageKey)
/**
* js中调用翻译代码示例方法一
*/
// let selectElement = document.getElementById('mySelect');
// // 定义选项数据
// let optionsData = [
// {
// value: '1',
// //这里以js文件中name为例进行翻译
// text: 'tel'
// },
// {
// value: '2',
// text: 'name'
// },
// ];
// console.log(optionsData,76)
// // 填充<select>元素
// optionsData.forEach(option => {
// const newOption = document.createElement('option');
// //给元素添加翻译标识
// newOption.setAttribute("data-translate",option.text)
// newOption.value = option.value;
// newOption.textContent = option.text;
// selectElement.appendChild(newOption);
// });
loadProperties(languageKey);
jsDemo();
});
/**
* js中调用翻译代码示例方法二
*/
async function jsDemo() {
let selectElement = document.getElementById('mySelect');
// 定义选项数据
let optionsData = [
{
value: '1',
//这里以js文件中name为例进行翻译
text: await getTextByTranslationKey('tel')
},
{
value: '2',
text: await getTextByTranslationKey('name')
},
];
// 填充<select>元素
optionsData.forEach(option => {
const newOption = document.createElement('option');
//给元素添加翻译标识
// newOption.setAttribute("data-translate",option.text)
newOption.value = option.value;
newOption.textContent = option.text;
selectElement.appendChild(newOption);
});
}
/**
* 语言切换事件监听切换后存cookie
*/
$(".lan_select").change(function () {
languageKey = $(".lan_select").val()
$.cookie("userLanguage", languageKey, {
expires: 7
});
loadProperties(languageKey);
location.reload();
});
/**
* 自动翻译页面内容
* @param type 语言包标识
*/
function loadProperties(type) {
$.i18n.properties({
name: 'strings', // 资源文件名称
path: 'languages/', // 资源文件所在目录路径
mode: 'map', // 模式:变量或 Map
language: type, // 对应的语言
cache: false,
encoding: 'UTF-8',
callback: function () {
// 回调方法
$('[data-translate]').each(function () {
//遍历每一个需要翻译的元素本次翻译text
var translationKey = $(this).data('translate');
$(this).text($.i18n.prop(translationKey));
});
$('[data-translate-placeholder]').each(function () {
//遍历每一个需要翻译的元素本次翻译placeholder
var translationKey = $(this).data('translate-placeholder');
$(this).attr("placeholder", $.i18n.prop(translationKey))
});
}
});
}
/**
* 获取指定翻译内容按钮点击执行方法---临时演示用可以删掉
*/
function getKeyClick() {
getTextByTranslationKey($("#data_key").val())
}
/**
* 主动翻译指定key
* @param translationKey 需要翻译的key
*/
function getTextByTranslationKey(translationKey) {
return new Promise((resolve, reject) => {
$.i18n.properties({
name: 'strings', // 资源文件名称
path: 'languages/', // 资源文件所在目录路径
mode: 'map', // 模式:变量或 Map
language: languageKey, // 对应的语言
cache: false,
encoding: 'UTF-8',
callback: function () {
// 回调方法
//这一行演示用,可以删掉
$("#data_key_text").text($.i18n.prop(translationKey))
resolve($.i18n.prop(translationKey))
}
});
})
}

View File

@ -0,0 +1,13 @@
name=name:
name_placeholder=Please enter name
tel=tel:
tel_placeholder=Please enter tel
email=email:
email_placeholder=Please enter email
address=address:
address_placeholder= Please enter address
choose=choose:
choose_placeholder=Please choose
save=save
reset=reset
test1=Specify translation content

View File

@ -0,0 +1,13 @@
name=姓名:
name_placeholder=请输入姓名
tel=电话:
tel_placeholder=请输入电话
email=邮箱:
email_placeholder=请输入邮箱
address=地址:
address_placeholder=请输入地址
choose=选择器:
choose_placeholder=请选择
save=保存
reset=重置
test1=指定翻译内容

BIN
演示视频.mp4 Normal file

Binary file not shown.