Bug 1613705 - [localization] part7: Re-enable custom locales argument to Localization. r=nika,emilio

Depends on D113570

Differential Revision: https://phabricator.services.mozilla.com/D113571
This commit is contained in:
Zibi Braniecki 2021-08-03 16:25:12 +00:00
Родитель 589182cc2e
Коммит dc735b20ee
10 изменённых файлов: 131 добавлений и 57 удалений

1
Cargo.lock сгенерированный
Просмотреть файл

@ -2823,7 +2823,6 @@ dependencies = [
"futures-channel",
"l10nregistry",
"l10nregistry-ffi",
"libc",
"moz_task",
"nserror",
"nsstring",

Просмотреть файл

@ -87,14 +87,14 @@ interface Localization {
* - aSync - Specifies if the initial state of the Localization API is synchronous.
* This enables a number of synchronous methods on the
* Localization API.
* - aBundleGenerator - an object with two methods - `generateBundles` and
* `generateBundlesSync` allowing consumers to overload the
* default generators provided by Gecko.
* - aRegistry - optional custom L10nRegistry to be used by this Localization instance.
* - aLocales - custom set of locales to be used for this Localization.
*/
[Throws]
constructor(sequence<UTF8String> aResourceIds,
optional boolean aSync = false,
optional L10nRegistry aRegistry);
optional L10nRegistry aRegistry,
optional sequence<UTF8String> aLocales);
/**
* A method for adding resources to the localization context.

Просмотреть файл

@ -142,53 +142,64 @@ already_AddRefed<Localization> Localization::Create(
Localization::Localization(const nsTArray<nsCString>& aResIds, bool aIsSync)
: mIsSync(aIsSync) {
ffi::localization_new(&aResIds, mIsSync, getter_AddRefs(mRaw));
ffi::localization_new(&aResIds, mIsSync, nullptr, getter_AddRefs(mRaw));
RegisterObservers();
}
Localization::Localization(nsIGlobalObject* aGlobal,
const nsTArray<nsCString>& aResIds, bool aIsSync)
: mGlobal(aGlobal), mIsSync(aIsSync) {
ffi::localization_new(&aResIds, mIsSync, getter_AddRefs(mRaw));
RegisterObservers();
}
ffi::localization_new(&aResIds, mIsSync, nullptr, getter_AddRefs(mRaw));
Localization::Localization(nsIGlobalObject* aGlobal,
const nsTArray<nsCString>& aResIds, bool aIsSync,
const L10nRegistry& aRegistry)
: mGlobal(aGlobal), mIsSync(aIsSync) {
ffi::localization_new_with_reg(&aResIds, mIsSync, aRegistry.Raw(),
getter_AddRefs(mRaw));
RegisterObservers();
}
Localization::Localization(nsIGlobalObject* aGlobal, bool aIsSync)
: mGlobal(aGlobal), mIsSync(aIsSync) {
nsTArray<nsCString> resIds;
ffi::localization_new(&resIds, mIsSync, getter_AddRefs(mRaw));
ffi::localization_new(&resIds, mIsSync, nullptr, getter_AddRefs(mRaw));
RegisterObservers();
}
Localization::Localization(nsIGlobalObject* aGlobal)
: mGlobal(aGlobal), mIsSync(false) {
nsTArray<nsCString> resIds;
ffi::localization_new(&resIds, mIsSync, getter_AddRefs(mRaw));
Localization::Localization(nsIGlobalObject* aGlobal, bool aIsSync,
const ffi::LocalizationRc* aRaw)
: mGlobal(aGlobal), mRaw(aRaw), mIsSync(aIsSync) {
RegisterObservers();
}
already_AddRefed<Localization> Localization::Constructor(
const GlobalObject& aGlobal, const Sequence<nsCString>& aResourceIds,
bool aIsSync, const Optional<NonNull<L10nRegistry>>& aRegistry,
ErrorResult& aRv) {
const Optional<Sequence<nsCString>>& aLocales, ErrorResult& aRv) {
nsTArray<nsCString> resIds = ToTArray<nsTArray<nsCString>>(aResourceIds);
Maybe<nsTArray<nsCString>> locales;
if (aLocales.WasPassed()) {
locales.emplace();
locales->SetCapacity(aLocales.Value().Length());
for (const auto& locale : aLocales.Value()) {
locales->AppendElement(locale);
}
}
RefPtr<const ffi::LocalizationRc> raw;
bool result = ffi::localization_new_with_locales(
&resIds, aIsSync,
aRegistry.WasPassed() ? aRegistry.Value().Raw() : nullptr,
locales.ptrOr(nullptr), getter_AddRefs(raw));
if (!result) {
aRv.ThrowInvalidStateError(
"Failed to create the Localization. Check the locales arguments.");
return nullptr;
}
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
if (aRegistry.WasPassed()) {
return do_AddRef(
new Localization(global, resIds, aIsSync, aRegistry.Value()));
} else {
return do_AddRef(new Localization(global, resIds, aIsSync));
}
return do_AddRef(new Localization(global, aIsSync, raw));
}
JSObject* Localization::WrapObject(JSContext* aCx,

Просмотреть файл

@ -38,6 +38,7 @@ class Localization : public nsIObserver,
const dom::GlobalObject& aGlobal,
const dom::Sequence<nsCString>& aResourceIds, bool aIsSync,
const dom::Optional<dom::NonNull<L10nRegistry>>& aRegistry,
const dom::Optional<dom::Sequence<nsCString>>& aLocales,
ErrorResult& aRv);
static already_AddRefed<Localization> Create(
const nsTArray<nsCString>& aResourceIds, bool aIsSync);
@ -79,12 +80,14 @@ class Localization : public nsIObserver,
protected:
Localization(const nsTArray<nsCString>& aResIds, bool aIsSync);
Localization(nsIGlobalObject* aGlobal, bool aIsSync);
Localization(nsIGlobalObject* aGlobal, const nsTArray<nsCString>& aResIds,
bool aIsSync);
Localization(nsIGlobalObject* aGlobal, const nsTArray<nsCString>& aResIds,
bool aIsSync, const L10nRegistry& aRegistry);
explicit Localization(nsIGlobalObject* aGlobal);
Localization(nsIGlobalObject* aGlobal, bool aIsSync);
Localization(nsIGlobalObject* aGlobal, bool aIsSync,
const ffi::LocalizationRc* aRaw);
virtual ~Localization();
void RegisterObservers();

Просмотреть файл

@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::xpcom_utils::get_app_locales;
use cstr::cstr;
use fluent_fallback::env::LocalesProvider;
use l10nregistry::{
@ -15,12 +16,19 @@ use std::{
ffi::CStr,
fmt::{self, Write},
};
use unic_langid::LanguageIdentifier;
use xpcom::interfaces;
#[derive(Clone)]
pub struct GeckoEnvironment;
pub struct GeckoEnvironment {
custom_locales: Option<Vec<LanguageIdentifier>>,
}
impl GeckoEnvironment {
pub fn new(custom_locales: Option<Vec<LanguageIdentifier>>) -> Self {
Self { custom_locales }
}
pub fn report_l10nregistry_setup_error(error: &L10nRegistrySetupError) {
warn!("L10nRegistry setup error: {}", error);
let result = log_simple_console_error(
@ -72,7 +80,16 @@ impl ErrorReporter for GeckoEnvironment {
impl LocalesProvider for GeckoEnvironment {
type Iter = std::vec::IntoIter<unic_langid::LanguageIdentifier>;
fn locales(&self) -> Self::Iter {
vec!["en-US".parse().unwrap()].into_iter()
if let Some(custom_locales) = &self.custom_locales {
custom_locales.clone().into_iter()
} else {
let result = get_app_locales()
.expect("Failed to retrieve app locales")
.into_iter()
.map(|s| LanguageIdentifier::from_bytes(&s).expect("Failed to parse a locale"))
.collect::<Vec<_>>();
result.into_iter()
}
}
}

Просмотреть файл

@ -105,7 +105,7 @@ fn get_packaged_locales() -> Vec<LanguageIdentifier> {
}
fn create_l10n_registry(sources: Option<Vec<FileSource>>) -> Rc<GeckoL10nRegistry> {
let env = GeckoEnvironment;
let env = GeckoEnvironment::new(None);
let mut reg = L10nRegistry::with_provider(env);
reg.set_adapt_bundle(GeckoBundleAdapter::default())
@ -166,7 +166,7 @@ pub enum L10nRegistryStatus {
#[no_mangle]
pub extern "C" fn l10nregistry_new(use_isolating: bool) -> *const GeckoL10nRegistry {
let env = GeckoEnvironment;
let env = GeckoEnvironment::new(None);
let mut reg = L10nRegistry::with_provider(env);
let _ = reg
.set_adapt_bundle(GeckoBundleAdapter { use_isolating })

Просмотреть файл

@ -59,7 +59,7 @@ pub extern "C" fn l10nfilesource_new(
FileSourceOptions { allow_override },
GeckoFileFetcher,
);
source.set_reporter(GeckoEnvironment);
source.set_reporter(GeckoEnvironment::new(None));
*status = L10nFileSourceStatus::None;
Rc::into_raw(Rc::new(source))
@ -113,7 +113,7 @@ pub unsafe extern "C" fn l10nfilesource_new_with_index(
GeckoFileFetcher,
index,
);
source.set_reporter(GeckoEnvironment);
source.set_reporter(GeckoEnvironment::new(None));
*status = L10nFileSourceStatus::None;
Rc::into_raw(Rc::new(source))
@ -165,7 +165,7 @@ pub extern "C" fn l10nfilesource_new_mock(
Default::default(),
fetcher,
);
source.set_reporter(GeckoEnvironment);
source.set_reporter(GeckoEnvironment::new(None));
*status = L10nFileSourceStatus::None;
Rc::into_raw(Rc::new(source))

Просмотреть файл

@ -76,6 +76,19 @@ pub fn get_packaged_locales() -> Option<ThinVec<nsCString>> {
Some(locales)
}
pub fn get_app_locales() -> Option<ThinVec<nsCString>> {
let locale_service =
get_service::<mozILocaleService>(cstr!("@mozilla.org/intl/localeservice;1"))?;
let mut locales = ThinVec::new();
unsafe {
locale_service
.GetAppLocalesAsBCP47(&mut locales)
.to_result()
.ok()?;
}
Some(locales)
}
pub fn set_available_locales(locales: &ThinVec<nsCString>) {
let locale_service =
get_service::<mozILocaleService>(cstr!("@mozilla.org/intl/localeservice;1"))

Просмотреть файл

@ -7,7 +7,6 @@ edition = "2018"
[dependencies]
futures-channel = "0.3"
futures = "0.3"
libc = "0.2"
nserror = { path = "../../../../xpcom/rust/nserror" }
nsstring = { path = "../../../../xpcom/rust/nsstring" }
l10nregistry = { git = "https://github.com/mozilla/l10nregistry-rs", rev = "55bf7f826d773303a67d8d7fdab099a04322d4fb" }

Просмотреть файл

@ -15,10 +15,11 @@ use l10nregistry_ffi::{
env::GeckoEnvironment,
registry::{get_l10n_registry, GeckoL10nRegistry},
};
use nserror::{nsresult, NS_OK};
use nsstring::{nsACString, nsCString};
use std::os::raw::c_void;
use std::{borrow::Cow, cell::RefCell};
use thin_vec::ThinVec;
use unic_langid::LanguageIdentifier;
use xpcom::{interfaces::nsrefcnt, RefCounted, RefPtr, Refcnt};
#[derive(Debug)]
@ -127,8 +128,19 @@ unsafe impl RefCounted for LocalizationRc {
}
impl LocalizationRc {
pub fn new(reg: &GeckoL10nRegistry, res_ids: Vec<String>, is_sync: bool) -> RefPtr<Self> {
let inner = Localization::with_env(res_ids, is_sync, GeckoEnvironment, reg.clone());
pub fn new(
res_ids: Vec<String>,
is_sync: bool,
registry: Option<&GeckoL10nRegistry>,
locales: Option<Vec<LanguageIdentifier>>,
) -> RefPtr<Self> {
let env = GeckoEnvironment::new(locales);
let inner = if let Some(reg) = registry {
Localization::with_env(res_ids, is_sync, env, reg.clone())
} else {
let reg = (*get_l10n_registry()).clone();
Localization::with_env(res_ids, is_sync, env, reg)
};
let loc = Box::new(LocalizationRc {
inner: RefCell::new(inner),
@ -393,30 +405,50 @@ impl LocalizationRc {
}
#[no_mangle]
pub extern "C" fn localization_new(
res_ids: &ThinVec<nsCString>,
is_sync: bool,
result: &mut *const LocalizationRc,
) -> nsresult {
*result = std::ptr::null();
let reg = get_l10n_registry();
let res_ids: Vec<String> = res_ids.iter().map(|res| res.to_string()).collect();
*result = RefPtr::forget_into_raw(LocalizationRc::new(&reg, res_ids, is_sync));
NS_OK
pub extern "C" fn localization_parse_locale(input: &nsCString) -> *const c_void {
let l: LanguageIdentifier = input.to_utf8().parse().unwrap();
Box::into_raw(Box::new(l)) as *const c_void
}
#[no_mangle]
pub extern "C" fn localization_new_with_reg(
pub extern "C" fn localization_new(
res_ids: &ThinVec<nsCString>,
is_sync: bool,
reg: &GeckoL10nRegistry,
reg: Option<&GeckoL10nRegistry>,
result: &mut *const LocalizationRc,
) {
*result = std::ptr::null_mut();
*result = std::ptr::null();
let res_ids: Vec<String> = res_ids.iter().map(|res| res.to_string()).collect();
*result = RefPtr::forget_into_raw(LocalizationRc::new(&reg, res_ids, is_sync));
*result = RefPtr::forget_into_raw(LocalizationRc::new(res_ids, is_sync, reg, None));
}
#[no_mangle]
pub extern "C" fn localization_new_with_locales(
res_ids: &ThinVec<nsCString>,
is_sync: bool,
reg: Option<&GeckoL10nRegistry>,
locales: Option<&ThinVec<nsCString>>,
result: &mut *const LocalizationRc,
) -> bool {
*result = std::ptr::null();
let res_ids: Vec<String> = res_ids.iter().map(|res| res.to_string()).collect();
let locales: Result<Option<Vec<LanguageIdentifier>>, _> = locales
.map(|locales| {
locales
.iter()
.map(|s| LanguageIdentifier::from_bytes(&s))
.collect()
})
.transpose();
if let Ok(locales) = locales {
*result = RefPtr::forget_into_raw(LocalizationRc::new(res_ids, is_sync, reg, locales));
true
} else {
false
}
}
#[no_mangle]