chromium 获取系统语言的过程

在网页的user-agent中,会标注出当前系统的语言,但是有时获取的语言并不是系统语言,始终是默认语言,特意通过代码来学习获取系统语言的过程。

首先在网页的js代码中,通过navigator的language这个属性来获取,navigator可以理解为一个浏览器的对象,包含了浏览器的基本信息,其中language属性就是当前系统的默认语言。


在chromium中,有一个navigator类来对应js中引用的navigator,navigator的定义如下

在src/third_party/WebKit/Source/core/frame/Navigator.h中:

namespace blink {

class LocalFrame;

class CORE_EXPORT Navigator final : public GarbageCollected<Navigator>,
                                    public NavigatorCPU,
                                    public NavigatorID,
                                    public NavigatorLanguage,
                                    public NavigatorOnLine,
                                    public ScriptWrappable,
                                    public DOMWindowClient,
                                    public Supplementable<Navigator> {
  DEFINE_WRAPPERTYPEINFO();
  USING_GARBAGE_COLLECTED_MIXIN(Navigator);

 public:
  static Navigator* create(LocalFrame* frame) { return new Navigator(frame); }
  ...
  // NavigatorLanguage
  Vector<String> languages() override;
  ...
  DECLARE_VIRTUAL_TRACE();

 private:
  explicit Navigator(LocalFrame*);
};

}  // namespace blink

以上代码中,主要是NavaigatorLanguage这个类,如下:


namespace blink {

class CORE_EXPORT NavigatorLanguage {
 public:
  NavigatorLanguage();

  AtomicString language();
  virtual Vector<String> languages() = 0;
  bool hasLanguagesChanged();
  void setLanguagesChanged();

 private:
  bool m_languagesChanged;
};


其中language()的实现如下:

AtomicString NavigatorLanguage::language() {
  return defaultLanguage();
}
}  // namespace blink
接下来,我们继续看看defaultLanguage()这个方法,
通过代码跳转,defaultLanguage()这个方法实现在 /src/third_party/Webkit/Source/platform/Language.cpp中,如下:
AtomicString defaultLanguage() {
  Vector<AtomicString>& override = preferredLanguagesOverride();
  if (!override.isEmpty())
    return override[0];
  return platformLanguage();
} 
static const AtomicString& platformLanguage() {
  DEFINE_STATIC_LOCAL(AtomicString, computedDefaultLanguage, ());
  if (computedDefaultLanguage.isEmpty()) {
    computedDefaultLanguage = AtomicString(
        canonicalizeLanguageIdentifier(Platform::current()->defaultLocale()));
    ASSERT(!computedDefaultLanguage.isEmpty());
  }
  return computedDefaultLanguage;
}

在defaultLanguage()中调用了同样在该文件中定义的platformLanguage()方法,而在platformLanguage()中,最终调用了defaultLocale()方法,

再次跳转到defaultLocale()的定义中,

/src/third_party/Webkit/public/platform/Platform.h 中:

// Returns a value such as "en-US".
virtual WebString defaultLocale() { return WebString(); 
}

从以上代码中知道,defaultLocale()被定义为一个虚函数,所以要找到override的地方,

根据子类列表中,确定了一个子类,/src/content/renderer/renderer_blink_platform_impl.cc中,如下:

WebString RendererBlinkPlatformImpl::defaultLocale() {
  return WebString::fromASCII(RenderThread::Get()->GetLocale());
}

接下来,继续追踪GetLocale()这个方法,

/src/content/public/renderer/render_thread.h中, 看到其声明:

virtual std::string GetLocale() = 0;

可以看到,GetLocale()方法是一个纯虚函数,所以要继续找到override该函数的地方

/src/content/renderer/render_thread_impl.cc 中,进行了override

std::string RenderThreadImpl::GetLocale() {
  // The browser process should have passed the locale to the renderer via the
  // --lang command line flag.
  const base::CommandLine& parsed_command_line =
      *base::CommandLine::ForCurrentProcess();
  const std::string& lang =
      parsed_command_line.GetSwitchValueASCII(switches::kLang);
  DCHECK(!lang.empty());
  return lang;
}

在以上代码中,看到其中的注释,locale是browser进程通过command line 传递到render进程,所以现在代码就进入到browser进程中,从之前的文件路径可以看出,

之前的操作都是在render中,现在就要开始进入到browser进程中,查找对kLanguage引用:

/src/ui/base/ui_base_switches.cc中,有KLang的定义:

// The language file that we want to try to open. Of the form
// language[-country] where language is the 2 letter code from ISO-639.
const char kLang[] = "lang";

kLang的引用,如下:

/src/content/browser/renderer_host/render_process_host_impl.cc中:

void RenderProcessHostImpl::AppendRendererCommandLine(
    base::CommandLine* command_line) {
  // Pass the process type first, so it shows first in process listings.
  command_line->AppendSwitchASCII(switches::kProcessType,
                                  switches::kRendererProcess);

  ...

  // Now send any options from our own command line we want to propagate.
  const base::CommandLine& browser_command_line =
      *base::CommandLine::ForCurrentProcess();
  PropagateBrowserCommandLineToRenderer(browser_command_line, command_line);

  // Pass on the browser locale.
  const std::string locale =
      GetContentClient()->browser()->GetApplicationLocale();
  command_line->AppendSwitchASCII(switches::kLang, locale);
  
  ...
}


在以上函数中,可以看到klang的值是通过GetContentClient()->browser()->GetApplicationLocale()这个方法来获取的,那么接下来就看看这个方法

/src/content/public/browser/content_browser_client.h中

  // Returns the locale used by the application.
  // This is called on the UI and IO threads.
  virtual std::string GetApplicationLocale();

其实现:

std::string ContentBrowserClient::GetApplicationLocale() {
  return "en-US";
}

可以看到,此处默认的是 “en-US”

目前通过测试,chromium在实际运行中,就是通过这个默认方法来返回当前的语言,所以要想设置语言,必须override这个方法,从设置browser的语言,

所以此处可以参考,chrome_browser_client来看看chrome是怎么处理这个语言值的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值