Typecho DIY多国语言支持教程

一个完整的多国语言功能包括:

随浏览器语言切换语言(此前博客已经实现)
用户可根据实际情况手动切换显示语言
文章内容多国语言适配(一篇文章, 多种语言可供切换)
注意:本文所述适用于Typecho 1.1, 其他版本应该不会有太大变化。

一、随浏览器语言切换语言
原理:
typecho原生自带了翻译功能, 但不支持随客户端语言自动切换。 因此获取客户端语言, 并替换原生翻译功能所调用的翻译文件即可。

注意:需要先开启Typecho原生的多国语功能。
关于原生的翻译功能 —> https://www.typechodev.com/case/typecho-language.html

更改Typecho根目录下/var/Typecho/I18n.php里的77行:


private static function init()
{
/* GetText支持 /
if (false === self::$_loaded && self::$_lang && file_exists(self::$_lang)) {
self::$_loaded = new Typecho_I18n_GetTextMulti(self::$_lang);
}
}

更改为如下:

private static function init()

{   
    /** 检查客户端语言 */
    if(!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])){
        $lang = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
            $langConfig = substr($lang,0,5);
        if(preg_match("/zh/i",$lang)){
            $langConfig = "zh_TW";
        }
        elseif(preg_match("/zh-cn/i",$lang)){
            $lang = "zh_CN";
        }
        else{
             $langConfig = "en_US";
        }
    }
    else{
        $langConfig = 'en_US';
    }

    /**检查是否有自定义语言 */
    if(Typecho_Cookie::get('__earthlog_autoLang')){
        $langConfig = Typecho_Cookie::get('__earthlog_autoLang');
    }
    else{
        Typecho_Cookie::set('__earthlog_autoLang', $langConfig);
    }
   
    $dir = defined('__TYPECHO_LANG_DIR__') ? __TYPECHO_LANG_DIR__ : __TYPECHO_ROOT_DIR__ . '/usr/langs';
    $langConfig = ($dir . '/' . $langConfig.".mo");

    /** GetText支持 */
    if (false === self::$_loaded && $langConfig && file_exists($langConfig)) {
        self::$_loaded = new Typecho_I18n_GetTextMulti($langConfig);
    }
}

注意, 这里替换成的代码和前一篇博客中的略有不同。

二、根据实际情况手动切换显示语言
原理:

通过COOKIE储存用户设置, 再载入时读取
用户切换语言后redirect回原网页
设置COOKIE - /admin/autoLang.php

Typecho没有这个文件, 需手动创建。

<?php
if (!defined('__DIR__')) {

define('__DIR__', dirname(__FILE__));

}

define('__TYPECHO_ADMIN__', true);

/* 载入配置文件 /
if (!defined('__TYPECHO_ROOT_DIR__') && !@include_once DIR . '/../config.inc.php') {

file_exists(__DIR__ . '/../install.php') ? header('Location: ../install.php') : print('Missing Config File');
exit;

}

/* 初始化组件 /
Typecho_Widget::widget('Widget_Init');

/* 注册一个初始化插件 /
Typecho_Plugin::factory('admin/common.php')->begin();

Typecho_Widget::widget('Widget_Options')->to($options);
Typecho_Widget::widget('Widget_User')->to($user);
Typecho_Widget::widget('Widget_Security')->to($security);
Typecho_Widget::widget('Widget_Menu')->to($menu);

/* 初始化上下文 /
$request = $options->request;
$response = $options->response;

//localhost/earthlog/admin/autoLang.php?setLang=en_US
Typecho_Cookie::set('__earthlog_autoLang', $_GET['setLang']);
$response->redirect($_GET['redirect']);
?>

建议添加后测试一下:

浏览器访问:

https://{你的域名/IP}/admin/autoLang.php?setLang=en_US&redirect=https://{你的域名/IP}

如果没有报错, 并且回到了首页, 即没问题。

将一下代码找到适当位置, 并添加到你的主题里的sidebar.php中:

<?php $here = 'https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; ?>


这是手动切换语言的入口。

三、文章内容多国语言适配(一篇文章, 多种语言可供切换)
原理:
通过再写文章/页面时同时写三种语言, 再在不同语言之间添加表示告诉程序这是什么语言即可。
为了不出现意外, 我们尽可能的从主题上入手。

主题编辑 - function.php(/usr/{主题名}/function.php):
这该文件的末尾添加如下函数(无需改动其他):

function getLang($content, $lang){

$pa = '%@'.$lang.'.*?@(.*?)@/'.$lang.'@%si';
preg_match_all($pa,$content,$match);
try{
    //return str_replace("@$lang@<br>" ,"" ,$match[0][0]);
    //return $match[1][0];
    return(str_replace("@/$lang@" , "",str_replace("@$lang@" , "",str_replace("@$lang@<br>" ,"" ,$match[0][0]))));
}
catch(Exception $e){
    return(False);
}

}

function _en($content){

print('<div style="
border-style: solid;
border-width: 1px;
display: block;
font-size: 0.81rem;
font-weight: normal;
margin-bottom: 1.25rem;
padding: 0.875rem 1.5rem 0.875rem 0.875rem;
position: relative;
transition: opacity 300ms ease-out;
border-color: #222;
">');
print($content);
print("</div>");

}

function _et($content, $needNotice = False){

try{
    /** 检查客户端语言 */
    if(!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])){
        $lang = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
            $langConfig = substr($lang,0,5);
        if(preg_match("/zh/i",$lang)){
            $langConfig = "zh_TW";
        }
        elseif(preg_match("/zh-cn/i",$lang)){
            $lang = "zh_CN";
        }
        else{
             $langConfig = "en_US";
        }
    }
    else{
        $langConfig = 'en_US';
    }

    /**检查是否有自定义语言 */
    if(Typecho_Cookie::get('__earthlog_autoLang')){
        $langConfig = Typecho_Cookie::get('__earthlog_autoLang');
    }
    else{
        Typecho_Cookie::set('__earthlog_autoLang', $langConfig);
    }

    
    if($langConfig == "zh_CN"){
        $langConfig = "zh_CN";
        $alternation = "zh_TW";
        $langNotice = array(
            0 => "<div class='tag-links'>已根据浏览器语言为您展示简体中文。</div>",
            1 => "<div class='tag-links'>很抱歉, 这篇文章没有提供简中内容。 我们将尝试为您显示繁中译文。</div>",
            2 => "<div class='tag-links'>很抱歉, 这篇文章没有提供简中内容。 我们将会为您显示英文译文。</div>",
            3 => "<div class='tag-links'>很抱歉, 这个页面没有启用多语言支持。</div>"
        );
    }
    elseif($langConfig == "zh_TW"){
        $langConfig = "zh_TW";
        $alternation = "zh_CN";
        $langNotice = array(
            0 => "<div class='tag-links'>已按照用戶端語言爲您顯示繁中譯文。</div>",
            1 => "<div class='tag-links'>糟糕, 本文不提供繁體中文譯文。 在此我們將試著展示简体中文譯文。</div>", 
            2 => "<div class='tag-links'>糟糕, 本文不提供繁體中文譯文。 在此我們將會爲您展示英文譯文。</div>", 
            3 => "<div class='tag-links'>抱歉, 此頁面尚未啓用多語言服務。</div>"
        );
    }
    else{
        $langConfig = "en_US";
        $alternation = "none";
        $langNotice = array(
            0 => "<div class='tag-links'>We are showing you a translated content by identified your browser.</div>",
            1 => "" ,
            2 => "" ,
            3 => "<div class='tag-links'>We apologize that the translated content is not provided to this page.</div>"
        );
    }

    $trans = getLang($content, $langConfig);
    /**如果不支持客户端语言 */
    if($trans == False){
        $trans = getLang($content, $alternation);

        /**如果不支持备选语言 */
        if($trans == False){
            $trans = getLang($content, "en_US");

            /**如果不支持英语 */
            if($trans == False){
                if($needNotice == True){
                    _en($langNotice[3]);
                }
                print($content);
            }
            else{
                if($needNotice == True){
                    _en($langNotice[2]);
                }
                print($trans);
            }
        }
        else{
            if($needNotice == True){
                _en($langNotice[1]);
            }
            print($trans);
        }
    }
    else{
        if($needNotice == True){
            _en($langNotice[0]);
        }
        print($trans);
    }
}
catch(Exception $e){
    print($content);
        if($needNotice == True){
    print("*It seems that the translated verison of this content is not supported.");
        }
}

}

保存, 关闭。

主题编辑 -> post.php(/usr/{主题名}/post.php)

将所有的

<?php $this->content(); ?>

改为:

<?php _et($this->content, True); ?>

记住, 是所有!

主题编辑 -> page.php(/usr/{主题名}/page.php)
将所有的

<?php $this->content(); ?>

改为:

<?php _et($this->content, True); ?>

主题编辑 -> index.php(/usr/{主题名}/index.php)

将所有的

<?php $this->content(); ?>

改为:

<?php _et($this->content); ?>
//注意, 这里和前面不一样了, 没有后面那个True。

主题编辑 -> archive.php(/usr/{主题名}/archive.php)
将所有的

<?php $this->content(); ?>

改为:

<?php _et($this->content); ?>
//注意, 这里和前面不一样了, 没有后面那个True。

四, 结尾
到现在, 其实这已经完成了整个多语言支持的搭建。
文章/独立页面的多语言支持需要所有文章使用一下模板编辑:

@zh_CN@
这里输入文章内容-简体中文
@/zh_CN@

@en_US@
Here to input Article content-English
@/en_US@

@zh_TW@
這裏錄入文章内容-繁體中文
@/zh_TW@

@NOTICE@
修改引号里的内容, 不要改动其他的。 如果不翻译就把所有东西删掉直接写, 如果其中一个语言不翻译就删掉那行就可。
@/NOTICE@

当然, 可以修改以下文件使这个模板在每次新建文章/页面使显示在编辑器中:

修改/admin/write-post.php 40行:

修改为:

修改/admin/write-page.php 36行:

修改为: