欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一次前端Vue項目國際化解決方案的實戰(zhàn)記錄

 更新時間:2024年07月29日 08:26:48   作者:蜘蛛上網(wǎng)  
這篇文章主要給大家介紹了關(guān)于前端Vue項目國際化解決方案的實戰(zhàn)記錄,以上只是一部分Vue項目開發(fā)中遇到的典型問題和解決方案,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

背景

有一個vue項目,要實現(xiàn)國際化功能,能夠切換中英文顯示,因為該項目系統(tǒng)的用戶包括了國內(nèi)和國外用戶。

需求

1、頁面表單上的所有中文標(biāo)簽要國際化,包括表單屬性標(biāo)簽、表格列頭標(biāo)簽等, title=“數(shù)量”;

2、輸入框的提示內(nèi)容需要國際化,如 placeholder=“選擇日期”

3、js代碼中的提示信息需要國際化,如 message(“請勾選批量設(shè)置”)、confirm(‘您確定要設(shè)置業(yè)務(wù)損耗嗎?’)、title: ‘刪除錯誤’ 等;

解決方案

1、開發(fā)流程,一開始開發(fā)過程中,我們不考慮國際化,等代碼基本完成后,最后再進行國際化;

2、考慮日后還可能由其他語種,所以這里我們做國際化詞語庫時,國際化編碼使用5位數(shù)字,對應(yīng)多種語言值,即一對多;

3、前端我們重新封裝一個全局方法 $lang(param1, param2) 來支持國際化,param1是國際化編碼,param2是默認值(如果國際化編碼沒找到對應(yīng)的語言單詞,則默認用param2,且去掉左右兩邊的 ‘~’符號);

(其實后來又分析了下,如果一開始前端開發(fā)人員把所有需要國際化的中文詞語,都寫成 $lang(‘中文詞語’) , $lang方法邏輯再修改下,如果沒有第二個參數(shù)并且第一個參數(shù)對應(yīng)的國際化詞語也沒有,則直接顯示第一個參數(shù)字符串,而且這樣的話,到后面再提取代碼中的需要國際化的內(nèi)容時就會很精確了。)

4、國際化流程:

  • 從前端代碼文件中將所有的中文提取出來,形成一個數(shù)組放到一個json文件中,并且數(shù)組需要去重一下;
  • 使用第三方的翻譯接口,來對導(dǎo)出的中文進行翻譯,生成一個中英文對照鍵值對json文件;
  • 校對中英文對照表,因為有的翻譯不一定準(zhǔn)確;
  • 根據(jù)校對后的中英文對照表,生成國際化編碼庫,并創(chuàng)建兩個國際化文件;
  • 根據(jù)校對后的中英文對照表,并分析代碼規(guī)則,將程序代碼中的中文進行國際化處理;

國際化流程實施

在國際化流程實施中,我使用編寫js腳本代碼來實現(xiàn)相關(guān)的處理,使用node環(huán)境來執(zhí)行腳本;

1、提取中文

從前端代碼文件中將所有的中文提取出來,形成一個數(shù)組放到一個json文件中,并且數(shù)組需要去重一下;

下面的代碼,是用來提取文件代碼中的中文的,我們可以將代碼文件命名為extractChinese.js,使用node來執(zhí)行該腳本;

代碼中要國際化的路徑設(shè)置的是當(dāng)前目錄下的src下的 components和pages文件夾

const fs = require('fs');  
const path = require('path');    
const chineseRegex = /[\u4e00-\u9fa5]+/g;  
  
function extractChineseFromFile(filePath) {  
  const content = fs.readFileSync(filePath, 'utf-8');  
  const chineseWords = content.match(chineseRegex);  
  return chineseWords || [];  
}  
  
function processDirectory(directoryPath) {  
  const files = fs.readdirSync(directoryPath);  
  const chineseSentences = [];  
  
  files.forEach((fileName) => {  
    const filePath = path.join(directoryPath, fileName);  
    const stats = fs.statSync(filePath);
  
    if (stats.isDirectory()) {  
      chineseSentences.push(...processDirectory(filePath));  
    } else if (stats.isFile() && ['.js', '.vue'].indexOf(path.extname(filePath)) > -1) {
      const chineseWords = extractChineseFromFile(filePath);  
      chineseSentences.push(...chineseWords);  
    }  
  });  
  
  return chineseSentences;  
}  
  
function main() {  
  const srcDirectory = path.join(__dirname, 'src');  
  const componentsDirectory = path.join(srcDirectory, 'components');  
  const pagesDirectory = path.join(srcDirectory, 'pages');  
  
  const componentsChineseSentences = processDirectory(componentsDirectory);  
  const pagesChineseSentences = processDirectory(pagesDirectory);  
  const allChineseSentences = [...componentsChineseSentences, ...pagesChineseSentences];  
  
  //const allChineseSentences = componentsChineseSentences;  
  
  const outputPath = path.join(__dirname, 'output.json'); 
  // 使用 Set 對象來去重  
  let backString = Array.from(new Set(allChineseSentences)); 
  // 對去重后的數(shù)組進行排序  
  backString.sort();
  fs.writeFileSync(outputPath, JSON.stringify(backString, null, 2), 'utf-8');  
  
  console.log('提取到的中文單詞或語句已保存到output.json文件中。');  
}  
  
main();

2、翻譯中文

使用第三方的翻譯接口,來對導(dǎo)出的中文進行翻譯,生成一個中英文對照鍵值對json文件;

翻譯接口,這里我們用的是百度翻譯,至于如何去使用百度翻譯,這里就不再說了,自己去百度看吧;

該步驟需要用到第一步生成的 output.json 文件,然后翻譯結(jié)果是存在 translated_zh_en.json 中。

const fs = require('fs');  
const axios = require('axios');  
const appId = '123456789'; // 替換成你的百度翻譯的APP ID  
const secretKey = '999999999'; // 替換成你的百度翻譯的密鑰  
  

const crypto = require('crypto');  
axios.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded;charset=UTF-8";
  
function md5Hash(input) {  
  // 創(chuàng)建一個哈希對象  
  const hash = crypto.createHash('md5');  
  
  // 更新哈希對象的內(nèi)容  
  hash.update(input);  
  
  // 獲取哈希值的二進制表示  
  const hashBuffer = hash.digest();  
  
  // 將二進制轉(zhuǎn)換為十六進制表示  
  const hashHex = hashBuffer.toString('hex');  
  
  // 返回小寫的哈希值  
  return hashHex.toLowerCase();  
}  
  
  
// 使用百度翻譯API進行翻譯  
async function translateToEnglish(text) { 
    const params = {  
        q: text,  
        appid: appId,  
        salt: Date.now(),  
        from: 'zh',  
        to: 'en',  
        sign: ''  
    };
        
    // 計算簽名  
    params.sign = md5Hash(params.appid + params.q + params.salt + secretKey);
    
    // 請求翻譯  
    const url = `http://api.fanyi.baidu.com/api/trans/vip/translate?q=${encodeURIComponent(params.q)}&from=zh&to=en&appid=${params.appid}&salt=${params.salt}&sign=${params.sign}`;
    const response = await axios.get(url); 
    //console.log(url);
    //console.log(response.data)
    // 返回翻譯結(jié)果  
    return response.data.trans_result[0].dst;  
}  

function sleep(ms) {  
  return new Promise(resolve => setTimeout(resolve, ms));  
}  
  
async function mysleep() {  
  console.log('休息1秒......................');  
  await sleep(1000); // 暫停 1 秒  
  console.log('休息完成...');  
} 
  
async function process() {  
    // 讀取json文件  
    const data = JSON.parse(fs.readFileSync('output.json', 'utf8'));  
    
    // 存儲翻譯結(jié)果的對象  
    let translationData = {};  
    
    let execNumber = 1;
    // 遍歷中文字符串?dāng)?shù)組,進行翻譯
    for (let i = 0; i < data.length; i++) {  
        const chineseString = data[i];  
        const englishString = await translateToEnglish(chineseString);  
        // 將原中文字符串和英文字符串形成鍵值對存儲到translationData對象中  
        translationData[chineseString] = englishString;
        
        if (execNumber >= 120) {   // 如果不想全部執(zhí)行,則執(zhí)行多少場退出
            break;
        } else if (i == execNumber*20) { // 每執(zhí)行20次接口調(diào)用,就休息1秒
            execNumber++;
            await mysleep()
        }
    }
     
    // 將翻譯結(jié)果寫入translate.json文件中  
    fs.writeFileSync('translated_zh_en.json', JSON.stringify(translationData, null, 2));  
}  
  
process().catch(error => {  
    console.error(error);  
});

3、校對翻譯

校對中英文對照表,因為有的翻譯不一定準(zhǔn)確;(找個行業(yè)英語水平高點的人,自己去校對吧)

4、創(chuàng)建國際化庫

根據(jù)校對后的中英文對照表,生成國際化編碼庫,并創(chuàng)建兩個國際化文件;

const fs = require('fs');  
  
// 讀取原始 JSON 文件  
const data = JSON.parse(fs.readFileSync('translated_zh_en.json', 'utf8'));  
  
// 中文和英文的 JSON 文件  
const chineseData = {};  
const englishData = {};  
  
let serialNumber = 00001;  
  
// 遍歷原始數(shù)據(jù),生成新的鍵值對  
for (let chinese in data) {  
  const english = data[chinese];  
  
  // 生成新的鍵值對,序號為 5 位數(shù)字  
  const key = `N${String(serialNumber).padStart(5, '0')}`;  
    
  chineseData[key] = chinese;  
  englishData[key] = english;  
  
  serialNumber++;  
}  
  
// 將中文和英文的 JSON 數(shù)據(jù)寫入文件  
fs.writeFileSync('cn.json', JSON.stringify(chineseData, null, 2));  
fs.writeFileSync('en.json', JSON.stringify(englishData, null, 2));

5、代碼國際化處理

根據(jù)第4步生成的中文國際化文件 cn.json ,并分析代碼規(guī)則,將程序代碼中的中文進行國際化處理;

首先要分析程序需要國際化的代碼規(guī)則,因為這個替換不是簡單的去就把中文替換,可能代碼都由變化,我們分析項目代碼中目前的規(guī)則如下:

場 景**代碼示例******查找內(nèi)容******替換內(nèi)容****
作為組件元素內(nèi)容的<vxe-button @click="closeModel">取消</vxe-button> <span style="color: red;">如調(diào)整了顏色尺碼,保存后請務(wù)必核對檢查數(shù)量和配色數(shù)據(jù)!</span> <div class="title">尺碼信息</div>>取消<>{{$lang(‘10000’, ‘取消’)}}<
作為組件元素屬性值的<vxe-table-column field="odgc_pcs" title="數(shù)量" width="100" header-align="center" align="right"> <el-date-picker v-if="row.type == 'date'" type="date" placeholder="選擇日期" v-model="row.value">title="數(shù)量"placeholder=“選擇日期”:title=“ l a n g ( ′ 1000 1 ′ , ′  數(shù)量   ′ ) " : p l a c e h o l d e r = " lang('10001', '~數(shù)量~')":placeholder=" lang(′10001′,′ 數(shù)量 ′)":placeholder="lang(‘Ph_select_data’, ‘選擇日期’)”
組件模板代碼中三元運算結(jié)果<el-button size="mini" @click="alterConsumption(row)">{{onlyShow?'查看':'修改'}}</el-button>‘查看’:‘查看’ ::‘修改’: ‘修改’l a n g ( ′ 1000 2 ′ , ′  查看   ′ ) 同上 lang('10002', '~查看~')同上 lang(′10002′,′ 查看 ′)同上lang(‘10003’, ‘修改’)同上
js 中方法參數(shù)值this.$XModal.message("請勾選批量設(shè)置", "error"); this.$XModal.confirm('您確定要設(shè)置嗎?') this.$confirm("確定要刪除此記錄嗎 ?", "提示", { confirmButtonText: "確定", cancelButtonText: "取消", type: "warning", })message("請勾選批量設(shè)置"message('請勾選要批量設(shè)置’confirm("您確定要設(shè)置嗎?"confirm(‘您確定要設(shè)置嗎?’“提示”,confirmButtonText: “確定”,cancelButtonText: “取消”,message(this. l a n g ( ′ 1000 4 ′ , ′  請勾選批量設(shè)置   ′ ) 同上 c o n f i r m ( t h i s . lang('10004', '~請勾選批量設(shè)置~')同上confirm(this. lang(′10004′,′ 請勾選批量設(shè)置 ′)同上confirm(this.lang(‘10005’, ‘您確定要設(shè)置嗎?’)同上this. l a n g ( ′ 1000 6 ′ , ′  提示   ′ ) , c o n f i r m B u t t o n T e x t : t h i s . lang('10006', '~提示~'),confirmButtonText: this. lang(′10006′,′ 提示 ′),confirmButtonText:this.lang(‘10007’, ‘確定’)cancelButtonText: this.$lang(‘10008’, ‘取消’)
js 中對象屬性賦值`this. X M o d a l . m e s s a g e ( m e s s a g e : " 保存失敗 " , s t a t u s : " e r r o r " ) ; t h i s . XModal.message({ message: "保存失敗", status: "error" }); this. XModal.message(message:"保存失敗",status:"error");this.message({ message: ‘請選擇要設(shè)置的物料!’, type: ‘warning’ }); this. X M o d a l . a l e r t ( m e s s a g e : " 請選擇附件分類 " , s t a t u s : " w a r n i n g " , ) ; t h i s . XModal.alert({ message: "請選擇附件分類", status: "warning", }); this. XModal.alert(message:"請選擇附件分類",status:"warning",);this.XModal.alert({ status: “error”, title: “刪除錯誤”, message: response.msg“服務(wù)器刪除發(fā)生錯誤”, });`
js 中 || 賦值`this.$XModal.alert({ status: “error”, title: “刪除錯誤”, message: response.msg“服務(wù)器刪除發(fā)生錯誤”, });`

替換的腳本代碼如下:

const fs = require('fs');
const path = require('path');

// 讀取 cn.json 文件并解析 JSON 數(shù)據(jù)  
function loadTranslations() {
    const cnJsonPath = path.join(__dirname, 'src', 'lang', 'cn.json');
    const content = fs.readFileSync(cnJsonPath, 'utf-8');
    return JSON.parse(content);
}

// 判斷字符串是否以指定前綴開頭  
function startsWith(str, prefix) {
    return str.startsWith(prefix);
}

/**
 * 每個鍵值對的場景匹配
 * @param {String} fileContent 文件內(nèi)容
 * @param {String} key 國際化變量名
 * @param {String} value 中文字符串
 */
function replaceAllScene(fileContent, key, value) {
    
    // 場景:>取消<
    let searchValue = `>${value}<`;
    let replaceValue = `>{{$lang('${key}', '~${value}~')}}<`;
    fileContent = fileContent.split(searchValue).join(replaceValue);  
    
    // 場景:title="數(shù)量"
    searchValue = `title="${value}"`;
    replaceValue = `:title="$lang('${key}', '~${value}~')"`;
    fileContent = fileContent.split(searchValue).join(replaceValue);
    
    // 場景:placeholder="選擇日期"
    searchValue = `placeholder="${value}"`;
    replaceValue = `:placeholder="$lang('${key}', '~${value}~')"`;
    fileContent = fileContent.split(searchValue).join(replaceValue);
    
    // 場景:message("請勾選批量設(shè)置"
    searchValue = `message("${value}"`;
    replaceValue = `message(this.$lang('${key}', '~${value}~')`;
    fileContent = fileContent.split(searchValue).join(replaceValue);
    // 場景:message('請勾選批量設(shè)置'
    searchValue = `message('${value}'`;
    replaceValue = `message(this.$lang('${key}', '~${value}~')`;
    fileContent = fileContent.split(searchValue).join(replaceValue);
    
    // 場景:confirm("您確定要設(shè)置業(yè)務(wù)損耗嗎?"
    searchValue = `confirm("${value}"`;
    replaceValue = `confirm(this.$lang('${key}', '~${value}~')`;
    fileContent = fileContent.split(searchValue).join(replaceValue);
    // 場景:confirm('您確定要設(shè)置業(yè)務(wù)損耗嗎?'
    searchValue = `confirm('${value}'`;
    replaceValue = `confirm(this.$lang('${key}', '~${value}~')`;
    fileContent = fileContent.split(searchValue).join(replaceValue);
    
    // confirmButtonText: "確定",
    searchValue = `confirmButtonText: "${value}",`;
    replaceValue = `confirmButtonText: this.$lang('${key}', '~${value}~'),`;
    fileContent = fileContent.split(searchValue).join(replaceValue);
    // cancelButtonText: "取消",
    searchValue = `cancelButtonText: "${value}",`;
    replaceValue = `cancelButtonText: this.$lang('${key}', '~${value}~'),`;
    fileContent = fileContent.split(searchValue).join(replaceValue);
    
    // message: "保存失敗"
    searchValue = `message: "${value}"`;
    replaceValue = `message: this.$lang('${key}', '~${value}~')`;
    fileContent = fileContent.split(searchValue).join(replaceValue);
    // message: '保存失敗''
    searchValue = `message: '${value}'`;
    replaceValue = `message: this.$lang('${key}', '~${value}~')`;
    fileContent = fileContent.split(searchValue).join(replaceValue);
    
    // title: "刪除錯誤"
    searchValue = `title: "${value}"`;
    replaceValue = `title: this.$lang('${key}', '~${value}~')`;
    fileContent = fileContent.split(searchValue).join(replaceValue);
    // title: '刪除錯誤'
    searchValue = `title: '${value}'`;
    replaceValue = `title: this.$lang('${key}', '~${value}~')`;
    fileContent = fileContent.split(searchValue).join(replaceValue);
    
    
    return fileContent;
}

// 在給定文件中替換指定的字符串  
function replaceStringsInFile(filePath, replacements) {
    const content = fs.readFileSync(filePath, 'utf-8');
    let newContent = content;

    for (const [key, value] of Object.entries(replacements)) {

        // 如果匹配到的字符串前面存在 "message(",則去掉左右兩邊的雙引號  
        //const searchValue = startsWith(value, 'message("') ? value.slice(8, -1) : value;

        newContent = replaceAllScene(newContent, key, value);

        //newContent = newContent.split(searchValue).join("$lang('" + key + "',')" + searchValue + "'");
    }

    if (newContent !== content) {
        fs.writeFileSync(filePath, newContent, 'utf-8');
        console.log(`Replaced strings in ${filePath}`);
    }
}

// 在指定目錄下處理所有文件  
function processDirectory(directoryPath, replacements) {
    const files = fs.readdirSync(directoryPath);

    files.forEach((fileName) => {
        const filePath = path.join(directoryPath, fileName);
        const stats = fs.statSync(filePath);

        if (stats.isDirectory()) {
            processDirectory(filePath, replacements);
        } else if (stats.isFile()) {
            replaceStringsInFile(filePath, replacements);
        }
    });
}

function main() {
    const translations = loadTranslations();
    const componentsDirectory = path.join(__dirname, 'src', 'components');
    const pagesDirPath = path.join(__dirname, 'src', 'pages');
    
    processDirectory(componentsDirectory, translations);
    processDirectory(pagesDirPath, translations);
}

main();

到此,我們就完成了前端代碼的國際化實現(xiàn);

我們?yōu)槭裁匆言形淖鳛?國際化方法 $lang 的第二個參數(shù)呢?

因為,如果代碼文件中看不到中文,修改代碼的時候太難找了,你只能看到國際化數(shù)字編碼。

建議

建議是在前端一開始開發(fā)的時候,就把需要國際化的地方都寫成 $lang(‘中文’),包括模板代碼和js代碼中,

這樣后期替換更精確,而且一開始開發(fā)人員也不用去管國際化,

并且,我們在提取代碼中文時,就可以按 $lang(‘中文’) 這個格式精確提取了,國際化處理后就變成 $lang(‘國際化編碼’,‘中文’) ,這樣我們在第二次再提取時,就不會重復(fù)提取已經(jīng)國際化處理后的代碼中文了。

總結(jié)

到此這篇關(guān)于一次前端Vue項目國際化解決方案的文章就介紹到這了,更多相關(guān)前端Vue項目國際化解決內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • element?ui?el-calendar日歷組件使用方法總結(jié)

    element?ui?el-calendar日歷組件使用方法總結(jié)

    這篇文章主要給大家介紹了關(guān)于element?ui?el-calendar日歷組件使用方法的相關(guān)資料,elementui是一款基于Vue.js的UI框架,其中的日歷組件calendar是elementui中非常常用的組件之一,需要的朋友可以參考下
    2023-07-07
  • 前端插件庫之vue3使用vue-codemirror插件的步驟和實例

    前端插件庫之vue3使用vue-codemirror插件的步驟和實例

    CodeMirror是一款基于JavaScript、面向語言的前端代碼編輯器,下面這篇文章主要給大家介紹了關(guān)于前端插件庫之vue3使用vue-codemirror插件的步驟和實例,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-07-07
  • 保姆級Vue3開發(fā)教程分享

    保姆級Vue3開發(fā)教程分享

    這篇Vue3開發(fā)文檔,包含了 Vue3 開發(fā)中使用的所有語法,文中的示例代碼講解詳細,希望所有像他一樣還不熟的伙伴快速上手 Vue3,不會的再不看要遭老罪咯
    2023-04-04
  • 一文帶你了解Vue中單文件組件的使用

    一文帶你了解Vue中單文件組件的使用

    在web開發(fā)中,組件化開發(fā)已成為一種趨勢,Vue提供了一種高效的方式來創(chuàng)建和管理這些組件—單文件組件,下面我們就來看看它的具體應(yīng)用吧
    2024-03-03
  • vue3獲取子組件的DOM元素的方法總結(jié)

    vue3獲取子組件的DOM元素的方法總結(jié)

    在 Vue 3 中,訪問子組件的 DOM 元素是一個常見的需求,本文將介紹如何在 Vue 3 中使用不同的方法來獲取子組件的 DOM 元素,需要的朋友可以參考下
    2023-08-08
  • echarts實現(xiàn)獲取datazoom的起始值(包括x軸和y軸)

    echarts實現(xiàn)獲取datazoom的起始值(包括x軸和y軸)

    這篇文章主要介紹了echarts實現(xiàn)獲取datazoom的起始值(包括x軸和y軸),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-07-07
  • Vue3更高效的構(gòu)建工具Vite使用指南

    Vue3更高效的構(gòu)建工具Vite使用指南

    這篇文章主要給大家介紹了關(guān)于Vue3更高效的構(gòu)建工具Vite使用的相關(guān)資料,Vite是一種面向現(xiàn)代瀏覽器的一個更輕、更快的前端構(gòu)建工具,能夠顯著提升前端的開發(fā)體驗,需要的朋友可以參考下
    2023-10-10
  • Vue 微信端掃描二維碼蘋果端卻只能保存圖片問題(解決方法)

    Vue 微信端掃描二維碼蘋果端卻只能保存圖片問題(解決方法)

    這幾天在做項目時遇到微信掃描二維碼的然后進入公眾號網(wǎng)頁巴拉巴拉的,然后就很順利的遇到了在安卓端掃碼的時候,順利的一塌糊涂,然后到了蘋果端的時候,就只能出現(xiàn)一個保存圖片,然后就寫一下記錄一下這問題的解決方法
    2020-01-01
  • 詳解Vue的異步更新實現(xiàn)原理

    詳解Vue的異步更新實現(xiàn)原理

    這篇文章主要介紹了Vue的異步更新實現(xiàn)原理,幫助大家更好的理解和使用vue,感興趣的朋友可以了解下
    2020-12-12
  • Vue中動態(tài)權(quán)限到按鈕的完整實現(xiàn)方案詳解

    Vue中動態(tài)權(quán)限到按鈕的完整實現(xiàn)方案詳解

    這篇文章主要為大家詳細介紹了Vue如何在現(xiàn)有方案的基礎(chǔ)上加入對路由的增、刪、改、查權(quán)限控制,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-03-03

最新評論