大專案中網頁多語系的維護方式

也許在許多專案上我們所說的Multi Language僅有繁體中文、簡體中文和英文,但在比較大型且跨國的專案上,可能會涉及更多的語言,例如:日文、俄文、德文、法文、西班牙文…等等,通常這些軟體內容的翻譯,需要經過更專業的單位來進行,也許這個單位不僅僅需要具備有這些國家的語言能力,也要具備有相當的軟體知識,才能配合當地民情翻譯出正確的文字,這部分往往需要專業的翻譯單位來進行。

而專業的翻譯單位通常並不具有軟體的製作能力,所以在軟體上要如何快速地進行協同作業,就變成一項非常重要的工作,而在許多專案上,我們會讓翻譯單位透過Excel來提供各國語系的翻譯文字,我們則透過軟體進行轉換,將其轉換至軟體能快速讀取的格式,講白一點就是將Excel檔案轉換成XML格式,並提供其他軟體進行讀取。

整體流程會如上圖所示,在拿到一個翻譯社提供所有語系的Excel資料後,我們會進行轉換,將文字轉換成多個XML檔案,並打包成一個ZIP檔讓轉換者進行下載。

今天我們主要來分享上圖藍色部分的處理程序,也就是那一隻轉換程式的結構和做法,我們將轉換程式設計成網頁版本,藉此提升易用性,而轉換程式操作Flow大致如下:

  1. 使用者上傳檔案(限制僅能上傳Excel檔案)
  2. 給出ZIP下載連結(提供使用者下載所有語系的XML檔)

操作上非常簡單,僅有上述這兩個步驟,而程式設計上採用JSP架構其運作邏輯如下:

  1. 檢查上傳檔案的格式、容量及相關資訊
  2. 擷取Excel中第一張工作表(也可以依照工作表名稱擷取)
  3. 將Excel中第一列視為語系標題,並當作存檔名稱(例如:English.xml)
  4. 將剩下來的每一列轉換為該檔案的語系資料,並建立XML檔案
  5. 將所有建立好的XML檔案進行打包(ZIP)
  6. 更新頁面產生ZIP檔下載路徑

在該轉換程式中,另外有利用到下述的JAVA Library:

  1. Apache POI – 處理與解析Excel檔案
  2. DOM4J – 建立XML檔案
  3. Apache Commons – 處理檔案上傳

以下是轉換的程式碼:

<%@ page contentType="text/html; charset=UTF-8"%>

<%@ page import="java.io.File"%>
<%@ page import="java.text.*" %>
<%@ page import="java.util.*" %>
<%@ page import="java.util.Iterator"%>
<%@ page import="java.util.List"%>
<%@ page import="org.apache.commons.fileupload.*"%>
<%@ page import="org.apache.commons.io.FilenameUtils"%>

<%@ page import="java.util.zip.ZipEntry"%>
<%@ page import="java.util.zip.ZipOutputStream"%>

<%@ page import="java.io.FileInputStream"%>
<%@ page import="java.io.FileOutputStream"%>
<%@ page import="java.io.IOException"%>
<%@ page import="java.io.OutputStreamWriter"%>
<%@ page import="java.nio.charset.Charset"%>

<%@ page import="org.apache.poi.hssf.usermodel.HSSFRow"%>
<%@ page import="org.apache.poi.hssf.usermodel.HSSFSheet"%>
<%@ page import="org.apache.poi.hssf.usermodel.HSSFWorkbook"%>

<%@ page import="org.dom4j.io.OutputFormat"%>
<%@ page import="org.dom4j.io.XMLWriter"%>
<%@ page import="org.dom4j.Document"%>
<%@ page import="org.dom4j.DocumentHelper"%>
<%@ page import="org.dom4j.Element"%>


<%!
    //允許上傳的檔案
  String allowedFileTypes = ".xls";
  
  //建立目錄
    public void newFolder(String folderPath) {
        try {
            String filePath = folderPath;
            filePath = filePath.toString();
            java.io.File myFilePath = new java.io.File(filePath);
            if (!myFilePath.exists()) {
                myFilePath.mkdir();
            }
        }
        catch(Exception e) {
            System.out.println("建立目錄錯誤");
            //e.printStackTrace();
        }
    }
   
   // 轉換XLS為XML的主程式 ; 參數1.欲轉換的Excel工作表編號; 參數2.轉換的檔案路徑與檔名; 參數3.XML儲存的檔案路徑;
   public static String convertSheet(int sheetNumber, String conversionFile, String conversionXMLFilePath) {
     
     String convertStatus = "0"; // 輸出轉換狀態 ; 0 是失敗; 1是成功
     String conversionXMLFileName = null; // XML檔名
     String conversionXMLFile = null; // XML完整路徑與檔名
     
     // 產生儲存XML檔案的資料夾
     File file = new File(conversionXMLFilePath);
     if(!file.exists()){
         file.mkdirs();
     }
     
     // 開始讀取XLS檔案
     HSSFWorkbook book = null;
     try {
       book = new HSSFWorkbook(new FileInputStream(conversionFile));
     } catch (IOException e) {
       System.out.println("IOException : " + e);
     }
     
     HSSFSheet sheet = book.getSheetAt(sheetNumber); // 打開對應編號的工作表
     HSSFRow row = sheet.getRow(0);// 取得工作表的第一列資料
     String cell;
     int totalRows = sheet.getPhysicalNumberOfRows(); // 取得工作表中所有的列數
     int totalCol = row.getPhysicalNumberOfCells(); // 取的工作表中所有的欄數
     
     // 開始建立XML檔並將XLS內容建入
     for (int j = 1; j < totalCol; j++){
       Document document = DocumentHelper.createDocument();
       Element root = document.addElement("root");
       
       for (int i = 0; i < totalRows; i++){
         row = sheet.getRow(i);
         try {
           cell = row.getCell(j).toString();
           if(i==0) {
             conversionXMLFileName = cell;
             conversionXMLFile = conversionXMLFilePath + conversionXMLFileName + ".xml";
           }else {
             root.addElement("row_" + (i+1)).addCDATA(cell);
             /*
             if(sheetNumber == 0) {
               root.addElement("tag_" + (i-1), cell);
             }else {
               root.addElement(xmlKeyboardTitle[(i-1)], cell);
             }
             */
           }
         } catch (NullPointerException e) {
           break;
         }
       }
       
       File storedFile = new File(conversionXMLFile);
       
       if(storedFile.exists())
         storedFile.delete();

       FileOutputStream fos = null;
       OutputStreamWriter osw = null;
       XMLWriter writer = null;
       try {
         storedFile.createNewFile();
         OutputFormat format = OutputFormat.createPrettyPrint();  
               format.setEncoding("utf-8");
               fos = new FileOutputStream(storedFile);
               osw = new OutputStreamWriter(fos, Charset.forName("utf-8"));
               writer = new XMLWriter(osw, format);
               writer.write(document);
       } catch (IOException e) {
         System.out.println("IOException : " + e);
       } finally {
         try {
           if(writer != null) writer.close();
           if(osw != null) osw.close();
           if(fos != null) fos.close();
           convertStatus = "1";
         } catch (IOException e) {
           System.out.println("IOException : " + e);
         }
       }
     }
     return convertStatus; // 回覆轉換狀態
   }
   
   List<String> filesListInDir = new ArrayList<String>();
   
   public void zipDirectory(File dir, String zipDirName) {
     
     filesListInDir = new ArrayList<String>();
     
        try {
          
            populateFilesList(dir);
            //now zip files one by one
            //create ZipOutputStream to write to the zip file
            FileOutputStream fos = new FileOutputStream(zipDirName);
            ZipOutputStream zos = new ZipOutputStream(fos);
            for(String filePath : filesListInDir){
                System.out.println("Zipping "+filePath);
                //for ZipEntry we need to keep only relative file path, so we used substring on absolute path
                ZipEntry ze = new ZipEntry(filePath.substring(dir.getAbsolutePath().length()+1, filePath.length()));
                zos.putNextEntry(ze);
                //read the file and write to ZipOutputStream
                FileInputStream fis = new FileInputStream(filePath);
                byte[] buffer = new byte[1024];
                int len;
                while ((len = fis.read(buffer)) > 0) {
                    zos.write(buffer, 0, len);
                }
                zos.closeEntry();
                fis.close();
            }
            zos.close();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
   
   private void populateFilesList(File dir) throws IOException {
        File[] files = dir.listFiles();
        for(File file : files){
            if(file.isFile()) filesListInDir.add(file.getAbsolutePath());
            else populateFilesList(file);
        }
    }
  
%>

<%

String messageReturn = "";
  
try{
  
    request.setCharacterEncoding("utf-8");
    DiskFileUpload fileUpload = new DiskFileUpload();
  List<FileItem> fileItems = fileUpload.parseRequest(request);
  FileItem fileItem = fileItems.get(0);
  
    //原始上傳檔案名稱
  String originalFileName = fileItem.getName();
    //out.print("originalFileName : " + originalFileName + "<br>");
    
  if (originalFileName != null && !"".equals(originalFileName)) {

        originalFileName = FilenameUtils.getName(originalFileName);
        String extension = FilenameUtils.getExtension(originalFileName);
        
    //判斷檔案格式是否允許
    //out.print("extension : " + extension + "<br>");
        if (allowedFileTypes.indexOf(extension.toLowerCase()) != -1) {
            String filePath = this.getServletContext().getRealPath(request.getRequestURI().substring(request.getContextPath().length()));
            String savePath = new File(filePath).getParent() + "/upload";
          //out.println("savePath = " + savePath + "<br>");
      newFolder(savePath);
      
          String savePathAndName = savePath + "/" + originalFileName;
            //out.print(savePathAndName);
      
          File f = new File(savePathAndName);
          if(!f.exists()){
            f.createNewFile();
          }
          fileItem.write(f);
            
            //messageReturn += "File path : " + savePath + "<br>";
            
             String xmlSavePath = savePath + "/xml/";
             //messageReturn += "xmlSavePath : " + xmlSavePath + "<br>";
            
            if("1".equals(convertSheet(0, savePathAndName , xmlSavePath))){
              messageReturn += "File converted successfully.<br>";
        }else{
          messageReturn += "File conversion failed.<br>";
        };
        
        /*
        xmlSavePath = savePath + "/xml/keyboard/";
        
        if("1".equals(convertSheet(1, savePathAndName , xmlSavePath))){
              messageReturn += "Keyboard sheet conversion succeeded.<br>";
        }else{
          messageReturn += "Keyboard sheet conversion fail.<br>";
        };
        */
      
        java.io.File myDelFile = new java.io.File(savePath + "/All.zip");
        myDelFile.delete();
        
        zipDirectory(new File(savePath + "/xml/"), savePath + "/All.zip");
        
        messageReturn += "<a href='upload/All.zip' target='_blank'>Download Link</a><br>";

        } else {
          messageReturn += "上傳錯誤 : 上傳的檔案不能是" + extension + ",僅允許xls格式<br>";
        }
    }
}catch(Exception e){
  //e.printStackTrace();
}

%>

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>AIOT CC Multi-Language Convertion Tool</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
    <style>
        *{
            font-family: 微軟正黑體;
        }
        h2{
            text-align: center;
        }
        .marginBottom20{
            margin-bottom: 20px;
        }
        #uploadBtn{
            margin: auto;
            display: block;
        }
        #messageDiv{
          color: red;
          text-align:center;
        }
    </style>
</head>

<body>

    <div class="container">
        <h2 class="marginBottom20">AIOT CC Multi-Language Convertion Tool</h2>
        <div class="form-group text-center">
          <form name="upload" enctype="multipart/form-data" method="post" action="index.jsp" onsubmit="return check_select()">
            <input type="file" name="file" id="file" size="60" maxlength="20" placeholder="*.xls" class="marginBottom20">
            <input id="uploadBtn" type="submit" value="轉換" class="btn btn-primary">
        </form>
      </div>
      <div id="messageDiv"><% out.print(messageReturn); %></div>
    </div>
    
</body>

</html>
<script>
    function check_select(form) {
        if (file.value == "") {
            alert("請選擇檔案");
            return false;
        } else {
            // document.getElementById("uploadBtn").disabled = true;
            //document.getElementById("msgDiv").innerHTML = "檔案上傳中,請稍候";
            return true;
        }
    }
</script>

You may also like...

86,412 Responses

  1. ScottBoume表示:

    legal online pharmacy coupon code: mexican pharmacy online – canadian pharmacy no prescription needed

  2. BruceRer表示:

    promo code for canadian pharmacy meds: mexican online pharmacy – cheapest pharmacy for prescriptions

  3. Irvincerce表示:

    how to get a prescription in canada: canada prescriptions by mail – canada pharmacy without prescription

  4. RobertSlata表示:

    https://edpills.guru/# ed doctor online

  5. BruceRer表示:

    online ed medication: edmeds – erectile dysfunction meds online

  6. BruceRer表示:

    best online pharmacy no prescription: mexican pharmacy online – canadian pharmacy coupon

  7. BruceRer表示:

    overseas pharmacy no prescription: mexican online pharmacy – rxpharmacycoupons

  8. ScottBoume表示:

    prescription drugs canada: pharmacy no prescription – online pharmacies no prescription usa

  9. ShawnWhism表示:

    http://pharmnoprescription.pro/# non prescription online pharmacy

  10. RobertSlata表示:

    https://onlinepharmacy.cheap/# buying prescription drugs from canada

  11. Patrickorilk表示:

    buy medication online no prescription pharmacy online no prescription buying drugs online no prescription

  12. BruceRer表示:

    online pharmacy no prescription: online mexican pharmacy – uk pharmacy no prescription

  13. ShawnWhism表示:

    https://onlinepharmacy.cheap/# rx pharmacy coupons

  14. ScottBoume表示:

    low cost ed medication: erectile dysfunction medications online – best online ed treatment

  15. Patrickorilk表示:

    no prescription canadian drugs no prescription pharmacy with no prescription

  16. RobertSlata表示:

    https://onlinepharmacy.cheap/# canadian pharmacy coupon

  17. RobertSlata表示:

    https://pharmnoprescription.pro/# no prescription needed pharmacy

  18. Irvincerce表示:

    online meds without prescription: purchasing prescription drugs online – online drugstore no prescription

  19. Patrickorilk表示:

    erectile dysfunction medicine online erectile dysfunction medicine online ed medications online

  20. ShawnWhism表示:

    https://pharmnoprescription.pro/# no prescription medicine

  21. ShawnWhism表示:

    https://pharmnoprescription.pro/# buy prescription drugs without a prescription

  22. Smoft表示:

    Some mini-games are like running towards the finish line at the end of the map or playing tag with other players. Players who cannot keep up with the pace of the mini-games will fall into the pink slime. In the final round, the remaining players will compete in the final match, and the game will decide a random mini-game, and the player who survives the last mini-game will be a winner.  The result, I’d argue, is that extraction shooters flip the script of BRs, and most other multiplayer shooters—the mandate to always be on offense is replaced with a suggestion to play more defensively. Playing a round of DMZ forces you to unlearn old habits, to approach gameplay from an entirely different angle, to reorganize your priorities. What’s great about Ring of Elysium is that it has the seriousness and FPS quality that you’re going to find in PUBG, but with a touch of the silliness of Fortnite. Real cat in a bubble-windowed carry backpack anyone? Yes, all of us. Not only does it have a seriously amazing character creation engine (seriously, I could tweak those dials all day), but it’s also an incredibly solid battle royale game, that’ll have you running from the ash storm on your BMX across Europa or aboard a skimobile on Dione. We’re obsessed, and so should you be. 
    https://handwiki.org/wiki/Company:JKLM_Games
    Have you tried Solitaire – Classic Card Game? Be the first to leave your opinion! You place a card on each of the seven rows, and then you turn the first card face-up. After that, you put a card on the last six rows, leaving out the first row, and then you turn over the first card in that column. You keep doing this until all rows have a face-up card. The aim of Spider Solitaire is to move all cards from the tableau to the foundation. For this purpose, you must arrange all cards in the tableau in descending order in the same suit, from King to Ace. Once you have completed a sequence, it will automatically be moved to the foundation and you can start on the next sequence and so on, until you have cleared the whole tableau. بلوتنا: A Free Card Game for Android Users Free Game for Cards Lovers

  23. ScottBoume表示:

    online pharmacy reviews no prescription: canadian prescriptions in usa – meds online without prescription

  24. Smoft表示:

    Despite the fact that the phrases game design and game development are sometimes used synonymously, they refer to two distinct ideas. The conceptual aspect of things is handled by game designers. They develop the first concept for a game. A designer is in charge of a game’s fundamental ideas, aesthetics, characters, levels, and stories. More information about our Cookie Policy Sources suggest that the Vivo Y200 5G price in India is slated to be below Rs 24,000. With such a competitive price point, it positions itself favorably in the mid-range smartphone market in India. This ensures vibrant and crisp images. Adding to its imaging prowess, the device will feature a 2MP portrait camera on the back. For selfie enthusiasts and video callers, a 16MP front camera will be included. This tarot deck pays tribute to the golden age of pixelated video games, drawing inspiration from the simplicity of pixel art graphics.
    https://wiki-nest.win/index.php?title=Game_online_candy_crush_saga
    • Euro Truck Simulator 2 – Iberia Update v1.41.1.25 incl DLC-CODEX Install Games If You want to play this game. So, in this article, we have provided Burnout 2 Takedown Game Download button. Just click the button & download it. Original First 2 Games • Euro Truck Simulator 2 – Iberia Update v1.40.5.0 incl DLC-CODEX • Euro Truck Simulator 2 – Iberia Update v1.41.1.25 incl DLC-CODEX Original First 2 Games Activision Games Blog Y 12 January, 202415 January, 2024 Game Features: World of Trucks is an optional service, registration on World of Trucks isn’t required to play the game. Z 看影音更棒 Y If you also want to play this game. And if you have come to our website for that, then you are at the right place. You Can Burnout 3 takedown pc Games on the ocean of games website.

  25. BruceRer表示:

    edmeds: ed prescriptions online – cheapest online ed treatment

  26. Smoft表示:

    Fortnite, the wildly popular online multiplayer game developed by Epic Games, has taken the gaming world by storm. With its engaging gameplay, vibrant graphics, and constant updates, it has captivated millions of players around the globe. Whether you’re a seasoned gamer or new to the world of gaming, Fortnite provides endless hours of entertainment on various devices, including tablets. The Dark Multiverse bundle will be available in the Fortnite item shop on October 26th, coinciding with the release of the Batman Fortnite: Foundation comic. This highly anticipated bundle brings the terrifying Batman Who Laughs to Season 8’s roster of characters, adding a dark twist to your gaming experience. Whether you’re a fan of the DC Universe or a Fortnite enthusiast looking for a new and menacing skin, this is an opportunity you won’t want to miss.
    https://augustjpom238902.blog2freedom.com/23313741/epic-games-free-games-this-week
    Ready to challenge other sports fans? Watch this video to learn how to play on Dream11 and get started now. Compete with sports fans, make a perfect Dream11 team with the best combination of players as per your knowledge and skill and win big. RNG stands for Random Number Generation. Skkily being RNG certified means that the number that appears on the cube or the cards you get are completely random and cannot be controlled by anyone. Ludo King is one of the most popular apps for playing ‘Ludo’, the board game. It’s always fun to play board games with friends and family. With this app, it’s easy and convenient to play the game on-the-go. Additionally, the app includes a version of Snakes & Ladders, just in case you want to try something different. With plenty of features and a simple interface, this is an engaging and interactive gaming app. Connecting people from around the world, Ludo King game download a great choice for a trip down memory lane.

  27. Smoft表示:

    ©1996-2024 IndiaMART 3:Start launching game by clicking on gta-vc.exe. How to use GTA San Andreas cheats on PCSave the game firstResume and type in the cheatThe GTA San Andreas cheat code will instantly activate Quikr: Homes, Jobs, Cars Etc Amongst the chief organizations of this domain, we are occupied in providing Moto GP 4 Racing Simulator Machine to our clients, which is highly demanded in the market. Business Type: Supplier | Trading Company Send a message to Tifs India Entertainment Company Amongst the chief organizations of this domain, we are occupied in providing Moto GP 4 Racing Simulator Machine to our clients, which is highly demanded in the market. Monday – Saturday | Timing 10.00am – 6.00pm Tifs India Entertainment Company Some considered MX Simulator just as heard to learn as riding a dirt bike but like the real life dirt bike, once the player figured out the right control and bike settings it offered hours of fun. Like other simulator games, MX Simulator provided awesome graphics and real life applications to riding a dirt bike.
    https://shanepoli063962.worldblogged.com/25815132/mahjong-dimensions-online
    Feed your employees’ competitive needs — even when working remotely — by organizing a trivia contest as one of your virtual happy hour games. You might have heard about Heads Up! before because it is the fun and hilarious game launched by Ellen DeGeneres and is now available on Zoom. For those who love playing charades games, Heads Up! is the perfect party game to spend time. What other games have you played on Zoom? Please leave a comment below. Only one person would need the physical game to make this work remotely. The guesser would just have to avert their eyes (and or ears) while other players learn the key word, and again while the clue-givers compare their clues to eliminate any duplicates. This traditional game is one of the best games for young children to play over Zoom or FaceTime. To play, one person gives simple instructions starting with “Simon Says”. The person receiving instruction should follow directions that start with “Simon Says”, but should *not* follow directions that do not start with “Simon Says”.

  28. Smoft表示:

    Copy and paste the HTML below into your website to make the above widget appear Privacy Policy For Kids Games Each incorrect click reduces your time by 10 seconds. Download this item grants you royalty free usage in unlimited projects Each incorrect click reduces your time by 10 seconds. Isometric tilemaps create the illusion of a 3D environment, and are extremely popular in 2D simulation, strategy, or RPG games. Some of these games include SimCity 2000, Pharaoh, or Final Fantasy Tactics. The below image shows an example of an atlas for an isometric tileset. Sheep Sheep – Arcade mahjong game with farm items. Fun cartoon game with many various elements. You need to collect three of the same items. Try to clear the game field to finish the level. Play this game on mobile devices and PC at Y8 anytime and have fun.
    https://midi.org/midi/forum/profile/148865-dressupgamesdev
    It is a common belief that rummy has complicated rules that makes it harder for people to indulge in rummy games. However, it is not true. Even though the card game features an initial learning curve and requires practice, it features simple and easy rules, making it easier for individuals to start playing. Real Cash Rummy is a version of the game where actual money is at stake. It’s hosted on online gaming platforms where players can deposit funds into their accounts for gameplay. The game functions on a buy-in system, where players contribute a specific amount to participate. Five points under Ten This thorough manual will guide you through all the Rummy game rules and terms in detail. To quickly look up single terms, take a look at our glossary! And use our game help to answer any questions coming up on the fly at the Rummy Palace.

  29. Patrickorilk表示:

    best online pharmacy no prescription canada online pharmacy pharmacy discount coupons

  30. BruceRer表示:

    buy erectile dysfunction pills: cheapest ed medication – online ed medications

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。