手机浏览 RSS 2.0 订阅 膘叔的简单人生 , 腾讯云RDS购买 | 超便宜的Vultr , 注册 | 登陆
浏览模式: 标准 | 列表全部文章

语言包?

本文也是转摘,不过看到它的时候,我想起了discuz的URL解析,discuz在做rewrite的时候,并没有主动都对模版中的链接进行更换,而是在输出前,对于符合规则的那些链接使用rewrite的规范进行了一次批量替换。

这次我转摘的文章也是用了类似的方法,只是他又是.NET处理的,我也不翻译了。知道了原理就行了(和discuz一样,不过这种方法应该只适合做语言包)

原文:

一直以来多语言问题都是个让人头疼的问题,不是这个问题有多难,而是很繁琐,而我们目前的这个项目有点特殊,我希望最大限度的化繁为简,以下是我解决这个问题的方案。
我们的项目有这样两个前提:
1、要支持多语言但最多三种语言,一般情况下就两种语言,所以并没有随时切换语言的要求。
2、我们希望有一种可以初期不用管语言问题,之后统一翻译的方案
基于这么两点,我们提出了这样的方案:
1、初期写程序时不用关心多语言的翻译工作,只要将所有使用到中文的地方都用{}扩上
2、在数据库中Chinese会设置为唯一约束
3、所有的翻译工作会在BasePage中的Render方法中作
4、所有的页面会继承BasePage
5、翻译时会根据当前的语言设置构建以language表中Chinese做key,相应的语言为value的字典,然后查找需要翻译的字符串是不是在字典中,如果不在就生成这一行。

 
数据库设计四个字段

ID,Chinese,English,Other

BasePage源码:

C#代码
  1. using System;  
  2. using System.Data;  
  3. using System.Configuration;  
  4. using System.Linq;  
  5. using System.Web;  
  6. using System.Web.Security;  
  7. using System.Web.UI;  
  8. using System.Web.UI.HtmlControls;  
  9. using System.Web.UI.WebControls;  
  10. using System.Web.UI.WebControls.WebParts;  
  11. using System.Xml.Linq;  
  12. using System.Text.RegularExpressions;  
  13. using System.Text;  
  14. using System.Collections;  
  15. using System.Collections.Generic;  
  16. using System.IO;  
  17. using System.Diagnostics;  
  18.   
  19. /// <summary>  
  20. ///BasePage 的摘要说明  
  21. /// </summary>  
  22. public class BasePage : System.Web.UI.Page  
  23. {  
  24.     //利用Dictionary来筛选所有的多语言标签,然后做替换,可以缓存  
  25.     Dictionary<stringstring> dic;  
  26.     public BasePage()  
  27.     {  
  28.   
  29.     }  
  30.     //需要替换的标签,标签头为数字字母下划线汉字  
  31.   
  32.     static readonly Regex re = new Regex  
  33.         (@"((\{)|(\%7B))[\w\-\+\|u4e00-\u9fa5]+?((\})|(\%7D))",  
  34.         RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);  
  35.   
  36.     //不需要替换的标签  
  37.     static readonly Regex re_nr = new  
  38.         Regex(@"<NOREPLACE>[\w\W]*?</NOREPLACE>", RegexOptions.Multiline | RegexOptions.IgnoreCase);  
  39.   
  40.     private string RenderTag(ref string content)  
  41.     {  
  42.         if (re_nr.IsMatch(content))//不需要替换标签  
  43.         {  
  44.             StringBuilder sb = new StringBuilder();  
  45.   
  46.             MatchCollection grouplist = re_nr.Matches(content);  
  47.             string[] reList = re_nr.Split(content);  
  48.   
  49.             for (int i = 0; i < grouplist.Count; i++)  
  50.             {  
  51.                 sb.Append(ReplaceTag(ref reList[i]));  
  52.                 sb.Append(grouplist[i].Value);  
  53.                 sb.Append(ReplaceTag(ref reList[i + 1]));  
  54.             }  
  55.   
  56.             content = sb.ToString();  
  57.         }  
  58.         else  
  59.         {  
  60.             content = ReplaceTag(ref content);  
  61.         }  
  62.         return content;  
  63.     }  
  64.   
  65.     private string ReplaceTag(ref string content)  
  66.     {  
  67.         //模板标签{yes},{no},{search}  
  68.         MatchCollection mc = re.Matches(content);  
  69.   
  70.         if (dic == null)  
  71.         {  
  72.             dic = LanguageManager.GetResource();  
  73.         }  
  74.   
  75.         for (int i = 0; i < mc.Count; i++)  
  76.         {  
  77.             //如果数据库中还没有此字符串  
  78.             if (!dic.ContainsKey(mc[i].Value.TrimStart('{').TrimEnd('}')))  
  79.             {  
  80.                  content = content.Replace(mc[i].Value, mc[i].Value.TrimStart('{').TrimEnd('}'));  
  81.   
  82.                 if (!dic.ContainsKey(mc[i].Value.TrimStart('{').TrimEnd('}')))  
  83.                 {  
  84.                     LanguageManager.AddLanguageString(mc[i].Value.TrimStart('{').TrimEnd('}'));  
  85.                 }  
  86.             }  
  87.             else if (dic[mc[i].Value.TrimStart('{').TrimEnd('}')] == null)  
  88.             {  
  89.                 content = content.Replace(mc[i].Value, "$$$$");  
  90.             }  
  91.             else  
  92.             {  
  93.   
  94.                 content = content.Replace(mc[i].Value, dic[mc[i].Value.TrimStart('{').TrimEnd('}')].ToString());  
  95.   
  96.   
  97.             }  
  98.         }  
  99.           
  100.         return content;  
  101.     }  
  102.     protected override void Render(HtmlTextWriter writer)  
  103.     {  
  104.   
  105.         Stopwatch stopwatch = new Stopwatch();  
  106.         stopwatch.Reset();  
  107.         stopwatch.Start();  
  108.         try  
  109.         {  
  110.             //会把页面的输出结果存储在这个StringBuilder中  
  111.             StringBuilder sb = new StringBuilder();  
  112.             StringWriter sw = new StringWriter(sb);  
  113.             HtmlTextWriter htw = new HtmlTextWriter(sw);  
  114.             base.Render(htw);  
  115.             string content = sb.ToString();  
  116.   
  117.             content = RenderTag(ref content);  
  118.   
  119.             //重新写入页面  
  120.             writer.Write(content);  
  121.   
  122.         }  
  123.         catch (Exception ex)  
  124.         {  
  125.             Response.Write(ex.ToString());  
  126.             Response.End();  
  127.         }  
  128.         finally  
  129.         {  
  130.             stopwatch.Stop();  
  131.             Response.Write("runtime:" + stopwatch.ElapsedMilliseconds.ToString() + "ms");  
  132.         }  
  133.   
  134.     }  
  135. }  
这样设计的
优点
1、初期写程序时不用关心多语言的翻译工作,只要将所有使用到中文的地方都用{}扩上
2、省去了大量命名相应文字的工作
3、直接用中文标示要显示到页面的文字,容易理解

缺点
1、如果中文是一样的翻译,而其他语言翻译却不一样时不好解决,但这种情况似乎不常见

————————END————————

缺点就是我说的,只能用来做语言包,呵呵。

Tags: web, 语言包, 数据库

参数编码 完全解决方案[ZZ]

GET和POST接收编码格式不一样?说实话,原先没有考虑过这些问题。因为在一个项目中,程序的编码由项目开始到结束肯定都会一样的,当然在ajax处理的时候可能会有点变化。毕竟ajax的东西采用了UTF8进行传递。除此之外,其他的编码一般来说都是一致的。在看到这篇文章的时候,觉得不错。同时也是提醒一下自己需要注意。
因为他的代码是.NET的,临时转载,就不翻译成PHP了,看看别人的思路就行了。。。
原文地址:http://www.cnblogs.com/zhangziqiu/archive/2009/01/20/encoding.html
原文:

在查阅了一天资料,做了很多的试验, 精简提炼语言后, 完成了下面的文章.我发现在项目中太多的程序员对编码,尤其是Web程序中的中文参数编码一知半解.本文将作为一种规范提出, 以后将会应用到我制作的项目中.希望能够对大家有所启示.

[参数编码规范]  

[原则]

避免在get或者post参数时直接传递中文字符.每次都经过指定格式的url编码后再传递.

[原因]

传递中文字符时,自动的编码解码格式和浏览器与服务器的设置有关.

测试Firefox3和IE6的Get方式发送中文参数, Firefox默认使用UTF-8格式编码中文参数, 而IE6即使在高级设置中设置了"总是以 UTF-8 发送URL", 仍然自动使用GB2312编码中文参数.

对于服务器端我们可以自由的控制解码的格式.但是往往是通过更改服务器配置进行全局的统一设置.比如对于ASP.NET程序.可以在Web.Config中设置服务器段的编码和解码格式:

XML/HTML代码
  1. <globalization culture="zh-CN" uiCulture="zh-CN" requestEncoding="UTF-8" responseEncoding="gb2312" />   

但是我们没法控制浏览器端行为.用户可能使用不同的浏览器.

   

[解决方案]

一.统一默认的编码格式

1.设置服务器端的编码格式为UTF-8

2.传递参数全部进行编码,.服务器端(C#)使用Server.UrlEncode方法,客户端(javascript)使用encodeURIComponent方法.

说明:

客户端的javascript函数encodeURIComponent只能使用UTF-8编码格式. 所以需要设置服务器端request和response都为UTF-8.

缺陷是如果某些合作伙伴必须传递其他的编码格式的参数, 则服务器端或获取到乱码.此方案实现简单,适合大部分场景.

   

二.通过编码参数指定编码格式

为了解决可能存在的无法统一编码格式的问题, 我们使用一个参数"encoding"来显示的指定编码格式.encoding参数需要在所有的请求中传递,无论是get还是post.

1.对于javascript客户端编码而言, 仍然使用encodeURIComponent方法编码, 此时指定encoding参数的值为"UTF-8".

2.对于传入给服务器端的 其他编码格式, 比如GB2312, 我们不能使用默认的Request.Form或者QueryString方法进行编码.因为服务器端的编码格式可能设置为了UTF-8.此时使用 Request.Form或者QueryString会自动使用服务器端指定的编码格式进行解码. 所以需要使用下面的方法自己处理请求,获取参数:

C#代码
  1. /**//// <summary>  
  2. /// 根据指定的编码格式返回请求的参数集合 ziqiu.zhang 2009.1.19  
  3. /// </summary>  
  4. /// <param name="request">当前请求的request对象</param>  
  5. /// <param name="encode">编码格式</param>  
  6. /// <returns>键为参数名,值为参数值的NameValue集合</returns>  
  7. public static NameValueCollection GetRequestParameters(HttpRequest request, string encode)  
  8. {  
  9.     NameValueCollection result = null;  
  10.     Encoding destEncode = null;  
  11.   
  12.     //根据指定的编码格式获取Encoding对象  
  13.     if (!String.IsNullOrEmpty(encode))  
  14.     {  
  15.         try  
  16.         {  
  17.             //获取指定的编码格式  
  18.             destEncode = Encoding.GetEncoding(encode);  
  19.         }  
  20.         catch   
  21.         {  
  22.             //如果获取指定编码格式失败,则默认为null  
  23.             destEncode = null;  
  24.         }  
  25.     }  
  26.   
  27.     //根据不同的HttpMethod方式,获取请求的参数.  
  28.     if (request.HttpMethod == "POST")  
  29.     {  
  30.         if (null != destEncode)  
  31.         {  
  32.             Stream resStream = request.InputStream;  
  33.             byte[] filecontent = new byte[resStream.Length];  
  34.             resStream.Read(filecontent, 0, filecontent.Length);  
  35.             string postquery = destEncode.GetString(filecontent);  
  36.             result = HttpUtility.ParseQueryString(postquery, destEncode);  
  37.         }  
  38.         else  
  39.         {  
  40.             result = request.Form;  
  41.         }  
  42.     }  
  43.     else  
  44.     {  
  45.         if (null != destEncode)  
  46.         {  
  47.             result = System.Web.HttpUtility.ParseQueryString(request.Url.Query, destEncode);  
  48.         }  
  49.         else  
  50.         {  
  51.             result = request.QueryString;  
  52.         }  
  53.     }  
  54.   
  55.     //返回结果  
  56.     return result;  
  57. }  
此方法的返回值是一个NameValueCollection集合.客户端实例代码如下:
C#代码
  1. protected override void OnLoad(EventArgs e)  
  2. {  
  3.     string sUrl = String.Empty;//来源页Url  
  4.     string tUrl = String.Empty;//目标页Url  
  5.     string encoding = String.Empty; //编码格式  
  6.   
  7.     Response.Clear();  
  8.   
  9.     try  
  10.     {  
  11.         //获取编码格式  
  12.         if (Request.HttpMethod.ToUpper().Trim() == "POST")  
  13.         {  
  14.             if (!String.IsNullOrEmpty(Request.Form["encoding"]))  
  15.             {  
  16.                 encoding = Request.Form["encoding"].ToUpper();  
  17.             }  
  18.         }  
  19.         else  
  20.         {  
  21.             if (!String.IsNullOrEmpty(Request.QueryString["encoding"]))  
  22.             {  
  23.                 encoding = Request.QueryString["encoding"].ToUpper();  
  24.             }  
  25.         }  
  26.   
  27.         //根据编码获取传递的参数列表  
  28.         NameValueCollection paramList = EncodeUtility.GetRequestParameters(Request, encoding);  
  29.   
  30.         //获取OrderFrom判断需要的参数  
  31.         sUrl = paramList["surl"];  
  32.         tUrl = paramList["turl"];  
  33.   
  34.         //获取OrderFrom的Cookies字符串  
  35.         if ( !( String.IsNullOrEmpty(sUrl) && String.IsNullOrEmpty(tUrl) ) )  
  36.         {  
  37.             Response.Write(OrderFromBL.OrderFromAnalysis(sUrl, tUrl));  
  38.         }  
  39.     }  
  40.     catch(Exception ex)  
  41.     {  
  42.         WebLog.CommentLog.CommonLogger.Error("OrderFromAjaxProxy.aspx页发生错误", ex);  
  43.     }  
  44.           
  45.     Response.End();  
  46. }  

如果没有传入encoding参数,则使用服务器端默认的编码方式.

   

[总结]

两种解决方案首先都是要做到避免使用浏览器的中文自动编码, 中文参数一定要先编码再传递. 同时统一客户端和服务器端的编码格式.

   [知识扩展]

   

[浏览器端的编码方式]

Get:

对于Get方式发送的请求, 不同的浏览器使用不同的编码方式自动为中文参数编码.比如:Firefox/3.0.5 使用UTF-8, IE6使用GB2312.

Post:

对于Post方式发送的 请求, 表单中的参数值对是通过request body发送给服务器,此时浏览器会根据网页的ContentType("text/html; charset=GBK")中指定的编码进行对表单中的数据进行编码,然后发给服务器。在HTML代码的Head中添加:
<meta http-equiv="Content-Type" content="text/html;charset=gb2312" />

Firefox/3.0.5 会使用根据charset中设置的编码格式编码post的中文参数.

IE6不起作用.

实验表明使用客户端浏览器默认编码格式具有不确定性.所以传递中文时我们要手工编码参数.

   

[Javascrip中的编码]

Javascrip语言中编码解码相关的方法主要有:

函数名称

函数说明

解释

escape()

escape() 函数可对字符串进行编码,这样就可以在所有的计算机上读取该字符串。

该方法不会对 ASCII 字母和数字进行编码,也不会对下面这些 ASCII 标点符号进行编码: - _ . ! ~ * ' ( ) 。其他所有的字符都会被转义序列替换。

   

[已过时] 请使用 encodeURI() 或 encodeURIComponent()

unescape()

unescape() 函数可对通过 escape() 编码的字符串进行解码。

该函数的工作原理是这样的:通过找到形式为 %xx 和 %uxxxx 的字符序列(x 表示十六进制的数字),用 Unicode 字符 \u00xx 和 \uxxxx 替换这样的字符序列进行解码。

   

[已过时] 请使用 decodeURI() 或 decodeURIComponent()

encodeURI()

encodeURI() 函数可把字符串作为 URI 进行编码。

  

该方法不会对 ASCII 字母和数字进行编码,也不会对这些 ASCII 标点符号进行编码: - _ . ! ~ * ' ( ) 。

该方法的目的是对 URI 进行完整的编码,因此对以下在 URI 中具有特殊含义的 ASCII 标点符号,encodeURI() 函数是不会进行转义的:;/?:@&=+$,#

   

[提示] 如果 URI 的参数中含有不能转移的字符,则应当使用 encodeURIComponent() 方法分别对各参数进行编码。

decodeURI()

decodeURI() 函数可对 encodeURI() 函数编码过的 URI 进行解码。

  

  

encodeURIComponent()

encodeURIComponent() 函数可把字符串作为 URI 组件进行编码。

  

该方法不会对 ASCII 字母和数字进行编码,也不会对这些 ASCII 标点符号进行编码: - _ . ! ~ * ' ( ) 。

其他字符(比如 :;/?:@&=+$,# 这些用于分隔 URI 组件的标点符号),都是由一个或多个十六进制的转义序列替换的。

   

[提示] 此方法会编码URI中的特殊字符

decodeURIComponent()

decodeURIComponent() 函数可对 encodeURIComponent() 函数编码的 URI 进行解码。

  

   

举例
document.write(encodeURIComponent("http://www.w3school.com.cn")+ "<br />")
document.write(encodeURI("http://www.w3school.com.cn")+ "<br />")

 结果
http%3A%2F%2Fwww.w3school.com.cn

http://www.w3school.com.cn

总结
对于一个URI(URL也是一中URI),如果我们希望将它作为完整的网址发送请求, 但是上面带有中文, 则应该使用encodeURI方法.

如果是要编码参数,则应该使用encodeURIComponent.

 


Tags: 编码, get, post, 方案

按照AdSense要求投放广告代码

虽然我的google adsense广告几乎没有人点,但是今天看到adsense小组说的重复投放的事情,还是有必要转帖一下,帮助其他人,免得重复 。。。

AdSense中文小组告诉我们:

自从我们发布了服务 器端广告设置这个功能以后,大家修改代码就更加方便了。Google AdSense代码投放的最好办法是直接通过帐户获取代码并嵌入到要投放的网站页面源代码中,但是我们发现有一些网站调整了AdSense广告代码的展 示。比如在一部分文学网站和一些内容管理系统中有类似于此的AdSense代码投放方式:

<div id="span_ad_01" style="display:none">
<script type="text/javascript"><!--
google_ad_client = "pub-1234512345123451";
google_ad_slot = "1234567890";
google_ad_width = 300;
google_ad_height = 250;
google_color_border = "E32BF1";
google_color_bg = "689BF1";
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div id=”span_ad_04”></div>
<script>
span_ad_04.innerHTML=span_ad_01.innerHTML;
span_ad_01.innerHTML="";
</script>


该种广告投放方式会导致一个广告位对系统产生多次广告查询,浏览器会多次处理这些请求,这样会影响用户体验。为了避免出现该问题,我们建议您按照以下方式修改广告代码:
1. 直接粘贴您的AdSense代码到页面源代码中
2. 通过iframe调用广告代码,但是一个页面只能嵌入一个iframe单元

AdSense 产品部门正在对广告后台进行一些调整以提升广告投放的准确性,如果您在使用类似上述原理的方式投放Google AdSense广告,那么接下来的这些调整可能会影响到您网站的广告投放。我们建议您尽快按照上述符合要求的方式投放AdSense广告,以避免接下来的 调整影响到您网站的AdSense广告投放。

我们注意到大家采用该方式以解决页面内容下载过慢的问题,但是从我们目前的数据和发布商反馈来看,AdSense广告在本地区的投放是不会影响页面内容下载的。

我们会通过系统邮件通知一部分以该方式投放代码的发布商,也希望大家相互转告,尽快实现代码的更换,以避免接下来的产品调整影响您网站的广告展示。如果您对此还有疑问,也欢迎通过支持链接和我们联系。

Tags: google, adsense

PHP框架:Treacle 介绍

群友Bopo自己开发了一个PHP的framework。Bopo从认识到现在,大概也有四五年的时间了吧,不过这个框架的年龄并不是特别长,大概只有2年多左右。最早这个框架BOPO是自己做项目的时候一点点的做的,但后来他终于有想法将它逐步扩大成为了一个框架。

最初看到框架的时候,还是一个雏型,现在,比以前好多了,所提供的支持也多了很多。让我们来看看这个糖浆究竟有些什么。

Treacle 是个什么呢?

Treacle 为开发者轻松、快捷的创建应用程序提供帮助。Treacle 框架简单、清晰,容易理解和学习,并且有完全中文化的文档和丰富的示例程序降低学习成本。

Treacle 有什么特点?

  • 完全跨平台
  • 完全支持 PHP5
  • 不倚赖特别的 PHP 扩展模块
  • 简单、容易理解的 MVC 模型
  • 丰富的助手对象和组件
  • 开放源代码,完全中文化的注释和文档
  • 商业公司提供技术支持

如何获取技术支持?

您可以通过参与我们的论坛来获得技术支持。
官方网址:http://www.treacle.cn/

可能现在有些简陋,但是期待一下吧。

Tags: framework, treacle, bopo

ThinkPHP发布1.5Lite版

一大早流年就在群里说发布了Lite版本,但是我还没有欣赏一下具体的代码,好象这个版本的想法是用Yhustc那里冒出来的,因为他的Yblog就自行对ThinkPHP 1.5进行了简化只保留了常用的功能,比如:数据库只支持MYSQL(也是,这个博客程序只用MYSQL,其他的一些驱动就可有可无了)。于是流年在这个想法的基础上,花了几天时间进行了Lite的构造。(估计几天的休息时间就这么没有了吧)

官方原文:http://www.thinkphp.cn/Blog/25

发布该版本的原因是很多应用开发要求较高的性能并且不需要很多特殊的功能

Lite版本提供网站开发最需要的功能,优化性能,更适合大型项目!

[ 功能列表 ]

编译缓存
自动生成
异常处理
URL模式
语言包支持
模板主题支持
空模块和空操作
前置和后置操作
智能数据表识别
自动加载
标签库
类库导入
Vendor支持
ADSL方法
跨库操作
字段映射
URL组装
URL伪静态
原生SQL操作
多数据库连接和切换
分布式数据库支持
支持MySql和PDO
惯例配置
项目配置
动态配置
模块配置
静态缓存
动态缓存
模板引擎和扩展支持
日志处理
SQL日志
调试模式
运行时间显示
页面Trace
类库扩展
自动验证
自动完成
CURD基本
AR模式基本
连贯操作

[ 注意事项 ]
去掉了ORG类库包(自己可以增加扩展)
保留文件缓存驱动
保留内置模板引擎和PHP模板引擎驱动
查询条件只支持字符串
CURD接口和数据库接口已经更改(和标准版不兼容)
视图模型和关联操作已经去掉
模型的数据操作保留了 add save delete find query execute 增加了select方法 并做了参数的调整
去掉了自动获取数据表字段信息 改由模型自己定义或者不定义
保留运行信息和页面Trace显示
去掉了URL路由功能(该部分功能可以用空模块和空操作取代)

[ 下载Lite版本 ]

Lite版本适合对TP有一定了解的开发人员,并且有PHP开发经验和足够的扩展能力。

Tags: thinkphp, lite